Skip to main content

wlancfg_lib/mode_management/
device_monitor.rs

1// Copyright 2018 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::legacy::{Iface, IfaceRef};
6use crate::mode_management::iface_manager_api::IfaceManagerApi;
7use crate::mode_management::phy_manager::PhyManagerApi;
8use anyhow::format_err;
9use fidl::endpoints::create_proxy;
10use fidl_fuchsia_wlan_common as fidl_common;
11use fidl_fuchsia_wlan_device_service::{DeviceMonitorProxy, DeviceWatcherEvent};
12use futures::lock::Mutex;
13use log::{error, info};
14use std::sync::Arc;
15
16pub struct Listener {
17    proxy: DeviceMonitorProxy,
18    legacy_shim: IfaceRef,
19    phy_manager: Arc<Mutex<dyn PhyManagerApi>>,
20    iface_manager: Arc<Mutex<dyn IfaceManagerApi>>,
21    power_manager: Arc<dyn wlan_power_manager::PowerManager>,
22}
23
24pub async fn handle_event(listener: &Listener, evt: DeviceWatcherEvent) {
25    info!("got event: {:?}", evt);
26    match evt {
27        DeviceWatcherEvent::OnPhyAdded { phy_id } => {
28            let _wake_lease =
29                listener.power_manager.take_wake_lease("wlancfg-device-phy-added").await;
30            on_phy_added(listener, phy_id).await;
31        }
32        DeviceWatcherEvent::OnPhyRemoved { phy_id } => {
33            let _wake_lease =
34                listener.power_manager.take_wake_lease("wlancfg-device-phy-removed").await;
35            info!("phy removed: {}", phy_id);
36            let mut phy_manager = listener.phy_manager.lock().await;
37            phy_manager.remove_phy(phy_id);
38        }
39        DeviceWatcherEvent::OnIfaceAdded { iface_id } => {
40            let _wake_lease =
41                listener.power_manager.take_wake_lease("wlancfg-device-iface-added").await;
42            // Ensure the new interface is usable by the policy internals before providing it to the
43            // legacy shim.
44            let mut iface_manager = listener.iface_manager.lock().await;
45            if let Err(e) = iface_manager.handle_added_iface(iface_id).await {
46                error!("Failed to add interface {} to IfaceManager: {}", iface_id, e);
47                return;
48            }
49
50            if let Err(e) = on_iface_added_legacy(listener, iface_id).await {
51                error!("error adding new iface {}: {}", iface_id, e)
52            }
53        }
54        DeviceWatcherEvent::OnIfaceRemoved { iface_id } => {
55            let _wake_lease =
56                listener.power_manager.take_wake_lease("wlancfg-device-iface-removed").await;
57            let mut iface_manager = listener.iface_manager.lock().await;
58            match iface_manager.handle_removed_iface(iface_id).await {
59                Ok(()) => {}
60                Err(e) => info!("Unable to record idle interface {}: {:?}", iface_id, e),
61            }
62
63            listener.legacy_shim.remove_if_matching(iface_id);
64            info!("iface removed: {}", iface_id);
65        }
66    }
67}
68
69async fn on_phy_added(listener: &Listener, phy_id: u16) {
70    info!("phy {} added", phy_id);
71    let mut phy_manager = listener.phy_manager.lock().await;
72    if let Err(e) = phy_manager.add_phy(phy_id).await {
73        info!("error adding new phy {}: {}", phy_id, e);
74        phy_manager.log_phy_add_failure();
75    }
76}
77
78/// Configured the interface that is used to service the legacy WLAN API.
79async fn on_iface_added_legacy(listener: &Listener, iface_id: u16) -> Result<(), anyhow::Error> {
80    let response = match listener.proxy.query_iface(iface_id).await? {
81        Ok(response) => response,
82        Err(zx::sys::ZX_ERR_NOT_FOUND) => {
83            return Err(format_err!("Could not find iface: {}", iface_id));
84        }
85        Err(status) => return Err(format_err!("Could not query iface information: {}", status)),
86    };
87
88    let service = listener.proxy.clone();
89
90    match response.role {
91        fidl_common::WlanMacRole::Client => {
92            let legacy_shim = listener.legacy_shim.clone();
93            let (sme, remote) = create_proxy();
94
95            let result = service
96                .get_client_sme(iface_id, remote)
97                .await
98                .map_err(|e| format_err!("Failed to get client SME: {}", e))?;
99            result.map_err(|e| {
100                format_err!("GetClientSme returned an error: {}", zx::Status::err_from_raw(e))
101            })?;
102
103            let lc = Iface { sme: sme.clone(), iface_id };
104            legacy_shim.set_if_empty(lc);
105        }
106        // The AP service make direct use of the PhyManager to get interfaces.
107        fidl_common::WlanMacRole::Ap => {}
108        fidl_common::WlanMacRole::Mesh => {
109            return Err(format_err!("Unexpectedly observed a mesh iface: {}", iface_id));
110        }
111        fidl_common::WlanMacRoleUnknown!() => {
112            return Err(format_err!(
113                "Unknown WlanMacRole type {:?} on iface {}",
114                response.role,
115                iface_id
116            ));
117        }
118    }
119
120    info!("new iface {} added successfully", iface_id);
121    Ok(())
122}
123
124impl Listener {
125    pub fn new(
126        proxy: DeviceMonitorProxy,
127        legacy_shim: IfaceRef,
128        phy_manager: Arc<Mutex<dyn PhyManagerApi>>,
129        iface_manager: Arc<Mutex<dyn IfaceManagerApi>>,
130        power_manager: Arc<dyn wlan_power_manager::PowerManager>,
131    ) -> Self {
132        Listener { proxy, legacy_shim, phy_manager, iface_manager, power_manager }
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    use super::*;
139    use crate::access_point::{state_machine as ap_fsm, types as ap_types};
140    use crate::client::types as client_types;
141    use crate::mode_management::Defect;
142    use crate::mode_management::iface_manager_api::{ConnectAttemptRequest, SmeForScan};
143    use crate::mode_management::phy_manager::{CreateClientIfacesReason, PhyManagerError};
144    use crate::mode_management::recovery::RecoverySummary;
145    use anyhow::Error;
146    use assert_matches::assert_matches;
147    use async_trait::async_trait;
148    use fidl_fuchsia_wlan_device_service as fidl_service;
149    use fidl_fuchsia_wlan_sme as fidl_sme;
150    use fuchsia_async as fasync;
151    use futures::StreamExt;
152    use futures::channel::oneshot;
153    use futures::task::Poll;
154    use ieee80211::MacAddr;
155    use std::collections::HashMap;
156    use std::pin::pin;
157
158    struct TestValues {
159        phy_manager: Arc<Mutex<FakePhyManager>>,
160        iface_manager: Arc<Mutex<FakeIfaceManager>>,
161        monitor_proxy: fidl_service::DeviceMonitorProxy,
162        monitor_stream: fidl_service::DeviceMonitorRequestStream,
163        power_manager: Arc<wlan_power_manager_testing::TestPowerManager>,
164    }
165
166    fn test_setup(add_phy_succeeds: bool, add_iface_succeeds: bool) -> TestValues {
167        let phy_manager =
168            Arc::new(Mutex::new(FakePhyManager::new(add_phy_succeeds, add_iface_succeeds)));
169        let iface_manager = Arc::new(Mutex::new(FakeIfaceManager::new()));
170        let (monitor_proxy, monitor_requests) = create_proxy::<fidl_service::DeviceMonitorMarker>();
171        let monitor_stream = monitor_requests.into_stream();
172        let power_manager = Arc::new(wlan_power_manager_testing::TestPowerManager::new());
173
174        TestValues { phy_manager, iface_manager, monitor_proxy, monitor_stream, power_manager }
175    }
176
177    #[fuchsia::test]
178    fn test_phy_add_succeeds() {
179        let mut exec = fasync::TestExecutor::new();
180        let test_values = test_setup(true, false);
181
182        let listener = Listener::new(
183            test_values.monitor_proxy,
184            IfaceRef::new(),
185            test_values.phy_manager.clone(),
186            test_values.iface_manager.clone(),
187            test_values.power_manager.clone(),
188        );
189
190        // Add Phy 0.
191        let fut = on_phy_added(&listener, 0);
192        let mut fut = pin!(fut);
193        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
194
195        // Verify that Phy 0 is now present
196        let list_phys_fut = async move {
197            let phy_manager = test_values.phy_manager.lock().await;
198            phy_manager.phys.clone()
199        };
200        let mut list_phys_fut = pin!(list_phys_fut);
201        let phys =
202            assert_matches!(exec.run_until_stalled(&mut list_phys_fut), Poll::Ready(phys) => phys);
203
204        assert_eq!(phys, vec![0]);
205    }
206
207    #[fuchsia::test]
208    fn test_phy_add_fails() {
209        let mut exec = fasync::TestExecutor::new();
210        let test_values = test_setup(false, false);
211
212        let listener = Listener::new(
213            test_values.monitor_proxy,
214            IfaceRef::new(),
215            test_values.phy_manager.clone(),
216            test_values.iface_manager.clone(),
217            test_values.power_manager.clone(),
218        );
219
220        // Add Phy 0.
221        let fut = on_phy_added(&listener, 0);
222        let mut fut = pin!(fut);
223        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
224
225        // Verify that Phy 0 was not added and its failure was logged.
226        let phy_manager_fut = async move {
227            let phy_manager = test_values.phy_manager.lock().await;
228            assert!(phy_manager.phys.is_empty());
229            assert_eq!(phy_manager.failed_phys, 1);
230        };
231        let mut phy_manager_fut = pin!(phy_manager_fut);
232        assert_matches!(exec.run_until_stalled(&mut phy_manager_fut), Poll::Ready(()));
233    }
234
235    #[fuchsia::test]
236    fn test_add_legacy_ap_iface() {
237        let mut exec = fasync::TestExecutor::new();
238        let mut test_values = test_setup(false, false);
239
240        let listener = Listener::new(
241            test_values.monitor_proxy,
242            IfaceRef::new(),
243            test_values.phy_manager.clone(),
244            test_values.iface_manager.clone(),
245            test_values.power_manager.clone(),
246        );
247
248        let fut = on_iface_added_legacy(&listener, 0);
249        let mut fut = pin!(fut);
250
251        // Run the future until it queries the interface's properties.
252        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
253
254        // Reply to the query indicating that this is an AP.
255        let iface_response = Some(fidl_service::QueryIfaceResponse {
256            role: fidl_common::WlanMacRole::Ap,
257            id: 0,
258            phy_id: 0,
259            phy_assigned_id: 0,
260            sta_addr: [0, 1, 2, 3, 4, 5],
261            factory_addr: [0, 1, 2, 3, 4, 5],
262        });
263        send_query_iface_response(&mut exec, &mut test_values.monitor_stream, iface_response);
264
265        // Nothing special should happen for the AP interface and the future should complete.
266        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Ok(())));
267    }
268
269    #[fuchsia::test]
270    fn test_add_legacy_unknown_iface() {
271        let mut exec = fasync::TestExecutor::new();
272        let mut test_values = test_setup(false, false);
273
274        let listener = Listener::new(
275            test_values.monitor_proxy,
276            IfaceRef::new(),
277            test_values.phy_manager.clone(),
278            test_values.iface_manager.clone(),
279            test_values.power_manager.clone(),
280        );
281
282        let fut = on_iface_added_legacy(&listener, 0);
283        let mut fut = pin!(fut);
284
285        // Run the future until it queries the interface's properties.
286        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
287
288        // Reply to the query indicating that this is an AP.
289        let iface_response = Some(fidl_service::QueryIfaceResponse {
290            role: fidl_common::WlanMacRole::unknown(),
291            id: 0,
292            phy_id: 0,
293            phy_assigned_id: 0,
294            sta_addr: [0, 1, 2, 3, 4, 5],
295            factory_addr: [0, 1, 2, 3, 4, 5],
296        });
297        send_query_iface_response(&mut exec, &mut test_values.monitor_stream, iface_response);
298
299        // The future should return an error in this case since an unknown WlanMacRole is not
300        // supported.
301        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
302    }
303
304    #[fuchsia::test]
305    fn test_add_legacy_mesh_iface() {
306        let mut exec = fasync::TestExecutor::new();
307        let mut test_values = test_setup(false, false);
308
309        let listener = Listener::new(
310            test_values.monitor_proxy,
311            IfaceRef::new(),
312            test_values.phy_manager.clone(),
313            test_values.iface_manager.clone(),
314            test_values.power_manager.clone(),
315        );
316
317        let fut = on_iface_added_legacy(&listener, 0);
318        let mut fut = pin!(fut);
319
320        // Run the future until it queries the interface's properties.
321        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
322
323        // Reply to the query indicating that this is a mesh interface.
324        let iface_response = Some(fidl_service::QueryIfaceResponse {
325            role: fidl_common::WlanMacRole::Mesh,
326            id: 0,
327            phy_id: 0,
328            phy_assigned_id: 0,
329            sta_addr: [0, 1, 2, 3, 4, 5],
330            factory_addr: [0, 1, 2, 3, 4, 5],
331        });
332        send_query_iface_response(&mut exec, &mut test_values.monitor_stream, iface_response);
333
334        // The future should return an error in this case since mesh is not supported.
335        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
336    }
337
338    #[fuchsia::test]
339    fn test_add_legacy_client_iface_succeeds() {
340        let mut exec = fasync::TestExecutor::new();
341        let mut test_values = test_setup(false, false);
342
343        let listener = Listener::new(
344            test_values.monitor_proxy,
345            IfaceRef::new(),
346            test_values.phy_manager.clone(),
347            test_values.iface_manager.clone(),
348            test_values.power_manager.clone(),
349        );
350
351        let fut = on_iface_added_legacy(&listener, 0);
352        let mut fut = pin!(fut);
353
354        // Run the future until it queries the interface's properties.
355        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
356
357        // Reply to the query indicating that this is a client.
358        let iface_response = Some(fidl_service::QueryIfaceResponse {
359            role: fidl_common::WlanMacRole::Client,
360            id: 0,
361            phy_id: 0,
362            phy_assigned_id: 0,
363            sta_addr: [0, 1, 2, 3, 4, 5],
364            factory_addr: [0, 1, 2, 3, 4, 5],
365        });
366        send_query_iface_response(&mut exec, &mut test_values.monitor_stream, iface_response);
367
368        // The future should stall again while requesting a client SME proxy.
369        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
370        assert_matches!(
371            exec.run_until_stalled(&mut test_values.monitor_stream.next()),
372            Poll::Ready(Some(Ok(fidl_service::DeviceMonitorRequest::GetClientSme {
373                iface_id: 0, sme_server: _, responder
374            }))) => {
375                assert!(responder.send(Ok(())).is_ok())
376            }
377        );
378
379        // The future should now run to completion.
380        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Ok(())));
381
382        // The listener should have a client interface.
383        assert!(listener.legacy_shim.get().is_ok());
384    }
385
386    #[fuchsia::test]
387    fn test_add_legacy_client_iface_fails() {
388        let mut exec = fasync::TestExecutor::new();
389        let mut test_values = test_setup(false, false);
390
391        let listener = Listener::new(
392            test_values.monitor_proxy,
393            IfaceRef::new(),
394            test_values.phy_manager.clone(),
395            test_values.iface_manager.clone(),
396            test_values.power_manager.clone(),
397        );
398
399        let fut = on_iface_added_legacy(&listener, 0);
400        let mut fut = pin!(fut);
401
402        // Run the future until it queries the interface's properties.
403        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
404
405        // Reply to the query indicating that this is a client.
406        let iface_response = Some(fidl_service::QueryIfaceResponse {
407            role: fidl_common::WlanMacRole::Client,
408            id: 0,
409            phy_id: 0,
410            phy_assigned_id: 0,
411            sta_addr: [0, 1, 2, 3, 4, 5],
412            factory_addr: [0, 1, 2, 3, 4, 5],
413        });
414        send_query_iface_response(&mut exec, &mut test_values.monitor_stream, iface_response);
415
416        // The future should stall again while requesting a client SME proxy.
417        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
418        assert_matches!(
419            exec.run_until_stalled(&mut test_values.monitor_stream.next()),
420            Poll::Ready(Some(Ok(fidl_service::DeviceMonitorRequest::GetClientSme {
421                iface_id: 0, sme_server: _, responder
422            }))) => {
423                assert!(responder.send(Err(zx::sys::ZX_ERR_NOT_FOUND)).is_ok())
424            }
425        );
426
427        // The future should now run to completion.
428        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
429
430        // The listener should not have a client interface.
431        assert!(listener.legacy_shim.get().is_err());
432    }
433
434    #[fuchsia::test]
435    fn test_add_legacy_client_iface_query_fails() {
436        let mut exec = fasync::TestExecutor::new();
437        let test_values = test_setup(false, false);
438
439        let listener = Listener::new(
440            test_values.monitor_proxy,
441            IfaceRef::new(),
442            test_values.phy_manager.clone(),
443            test_values.iface_manager.clone(),
444            test_values.power_manager.clone(),
445        );
446
447        // Drop the monitor stream so the QueryIface request fails.
448        drop(test_values.monitor_stream);
449
450        let fut = on_iface_added_legacy(&listener, 0);
451        let mut fut = pin!(fut);
452
453        // Run the future should immediately return an error.
454        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
455
456        // The listener should not have a client interface.
457        assert!(listener.legacy_shim.get().is_err());
458    }
459
460    #[fuchsia::test]
461    fn test_handle_add_phy_event() {
462        let mut exec = fasync::TestExecutor::new();
463        let test_values = test_setup(true, false);
464
465        let listener = Listener::new(
466            test_values.monitor_proxy,
467            IfaceRef::new(),
468            test_values.phy_manager.clone(),
469            test_values.iface_manager.clone(),
470            test_values.power_manager.clone(),
471        );
472
473        // Simulate an OnPhyAdded event
474        let fut = handle_event(&listener, DeviceWatcherEvent::OnPhyAdded { phy_id: 0 });
475        let mut fut = pin!(fut);
476        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
477
478        // Verify that Phy 0 is now present
479        let list_phys_fut = async move {
480            let phy_manager = test_values.phy_manager.lock().await;
481            phy_manager.phys.clone()
482        };
483        let mut list_phys_fut = pin!(list_phys_fut);
484        let phys =
485            assert_matches!(exec.run_until_stalled(&mut list_phys_fut), Poll::Ready(phys) => phys);
486
487        assert_eq!(phys, vec![0]);
488    }
489
490    #[fuchsia::test]
491    fn test_handle_remove_phy_event() {
492        let mut exec = fasync::TestExecutor::new();
493        let test_values = test_setup(false, false);
494
495        // Preload a fake PHY ID into the PhyManager
496        {
497            let phy_manager = test_values.phy_manager.clone();
498            let add_phy_fut = async move {
499                let mut phy_manager = phy_manager.lock().await;
500                phy_manager.phys.push(0);
501            };
502            let mut add_phy_fut = pin!(add_phy_fut);
503            assert_matches!(exec.run_until_stalled(&mut add_phy_fut), Poll::Ready(()));
504        }
505
506        let listener = Listener::new(
507            test_values.monitor_proxy,
508            IfaceRef::new(),
509            test_values.phy_manager.clone(),
510            test_values.iface_manager.clone(),
511            test_values.power_manager.clone(),
512        );
513
514        // Simulate an OnPhyRemoved event.
515        let fut = handle_event(&listener, DeviceWatcherEvent::OnPhyRemoved { phy_id: 0 });
516        let mut fut = pin!(fut);
517        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
518
519        // Verify that the PHY ID is no longer present
520        let list_phys_fut = async move {
521            let phy_manager = test_values.phy_manager.lock().await;
522            phy_manager.phys.clone()
523        };
524        let mut list_phys_fut = pin!(list_phys_fut);
525        let phys =
526            assert_matches!(exec.run_until_stalled(&mut list_phys_fut), Poll::Ready(phys) => phys);
527
528        assert!(phys.is_empty());
529    }
530
531    #[fuchsia::test]
532    fn test_handle_remove_nonexistent_iface_event() {
533        let mut exec = fasync::TestExecutor::new();
534        let test_values = test_setup(false, false);
535
536        // Load a fake iface ID into the IfaceManager.
537        {
538            let iface_manager = test_values.iface_manager.clone();
539            let add_iface_fut = async move {
540                let mut iface_manager = iface_manager.lock().await;
541                iface_manager.ifaces.push(0);
542            };
543            let mut add_iface_fut = pin!(add_iface_fut);
544            assert_matches!(exec.run_until_stalled(&mut add_iface_fut), Poll::Ready(()));
545        }
546
547        // Setup the Listener to look like it has an interface.
548        let (sme, _) = create_proxy::<fidl_sme::ClientSmeMarker>();
549        let iface_ref = IfaceRef::new();
550        iface_ref.set_if_empty(Iface { sme, iface_id: 0 });
551
552        let listener = Listener::new(
553            test_values.monitor_proxy,
554            iface_ref,
555            test_values.phy_manager.clone(),
556            test_values.iface_manager.clone(),
557            test_values.power_manager.clone(),
558        );
559
560        // Run the iface removal handler.
561        let fut = handle_event(&listener, DeviceWatcherEvent::OnIfaceRemoved { iface_id: 123 });
562        let mut fut = pin!(fut);
563        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
564
565        // The IfaceRef should still have its interface.
566        assert!(listener.legacy_shim.get().is_ok());
567    }
568
569    #[fuchsia::test]
570    fn test_handle_remove_iface_event() {
571        let mut exec = fasync::TestExecutor::new();
572        let test_values = test_setup(false, false);
573
574        // Load a fake iface ID into the IfaceManager.
575        {
576            let iface_manager = test_values.iface_manager.clone();
577            let add_iface_fut = async move {
578                let mut iface_manager = iface_manager.lock().await;
579                iface_manager.ifaces.push(0);
580            };
581            let mut add_iface_fut = pin!(add_iface_fut);
582            assert_matches!(exec.run_until_stalled(&mut add_iface_fut), Poll::Ready(()));
583        }
584
585        // Setup the Listener to look like it has an interface.
586        let (sme, _) = create_proxy::<fidl_sme::ClientSmeMarker>();
587        let iface_ref = IfaceRef::new();
588        iface_ref.set_if_empty(Iface { sme, iface_id: 0 });
589
590        let listener = Listener::new(
591            test_values.monitor_proxy,
592            iface_ref,
593            test_values.phy_manager.clone(),
594            test_values.iface_manager.clone(),
595            test_values.power_manager.clone(),
596        );
597
598        // Run the iface removal handler.
599        let fut = handle_event(&listener, DeviceWatcherEvent::OnIfaceRemoved { iface_id: 0 });
600        let mut fut = pin!(fut);
601        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
602
603        // The PhyManager and IfaceManager should have no reference to the interface.
604        {
605            let phy_manager = test_values.phy_manager.clone();
606            let iface_manager = test_values.iface_manager.clone();
607            let verify_fut = async move {
608                let phy_manager = phy_manager.lock().await;
609                let iface_manager = iface_manager.lock().await;
610                assert!(phy_manager.ifaces.is_empty());
611                assert!(iface_manager.ifaces.is_empty());
612            };
613            let mut verify_fut = pin!(verify_fut);
614            assert_matches!(exec.run_until_stalled(&mut verify_fut), Poll::Ready(()));
615        }
616
617        // The IfaceRef should be empty.
618        assert!(listener.legacy_shim.get().is_err());
619    }
620
621    #[fuchsia::test]
622    fn test_handle_iface_added_succeeds() {
623        let mut exec = fasync::TestExecutor::new();
624        let mut test_values = test_setup(false, true);
625
626        let listener = Listener::new(
627            test_values.monitor_proxy,
628            IfaceRef::new(),
629            test_values.phy_manager.clone(),
630            test_values.iface_manager.clone(),
631            test_values.power_manager.clone(),
632        );
633
634        let fut = handle_event(&listener, DeviceWatcherEvent::OnIfaceAdded { iface_id: 0 });
635        let mut fut = pin!(fut);
636
637        // The future should stall out while performing the legacy add interface routine.
638        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
639
640        // Reply to the query indicating that this is a client.
641        let iface_response = Some(fidl_service::QueryIfaceResponse {
642            role: fidl_common::WlanMacRole::Client,
643            id: 0,
644            phy_id: 0,
645            phy_assigned_id: 0,
646            sta_addr: [0, 1, 2, 3, 4, 5],
647            factory_addr: [0, 1, 2, 3, 4, 5],
648        });
649        send_query_iface_response(&mut exec, &mut test_values.monitor_stream, iface_response);
650
651        // The future should stall again while requesting a client SME proxy.
652        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
653        assert_matches!(
654            exec.run_until_stalled(&mut test_values.monitor_stream.next()),
655            Poll::Ready(Some(Ok(fidl_service::DeviceMonitorRequest::GetClientSme {
656                iface_id: 0, sme_server: _, responder
657            }))) => {
658                assert!(responder.send(Ok(())).is_ok())
659            }
660        );
661
662        // The future should not run to completion
663        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
664
665        // Verify that the IfaceManager has been notified of the new interface.
666        {
667            let iface_manager = test_values.iface_manager.clone();
668            let verify_fut = async move {
669                let iface_manager = iface_manager.lock().await;
670                assert_eq!(iface_manager.ifaces, vec![0]);
671            };
672            let mut verify_fut = pin!(verify_fut);
673            assert_matches!(exec.run_until_stalled(&mut verify_fut), Poll::Ready(()));
674        }
675
676        // The IfaceRef should have also been updated.
677        assert!(listener.legacy_shim.get().is_ok());
678    }
679
680    #[fuchsia::test]
681    fn test_handle_iface_added_fails_due_to_monitor_service() {
682        let mut exec = fasync::TestExecutor::new();
683        let test_values = test_setup(false, true);
684
685        let listener = Listener::new(
686            test_values.monitor_proxy,
687            IfaceRef::new(),
688            test_values.phy_manager.clone(),
689            test_values.iface_manager.clone(),
690            test_values.power_manager.clone(),
691        );
692
693        // Drop the monitor stream so that querying the interface fails while attempting to create
694        // the legacy shim.
695        drop(test_values.monitor_stream);
696
697        // Handle the interface addition and expect it to complete immediately.
698        let fut = handle_event(&listener, DeviceWatcherEvent::OnIfaceAdded { iface_id: 0 });
699        let mut fut = pin!(fut);
700        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
701
702        // Verify that the IfaceManager is updated.
703        {
704            let iface_manager = test_values.iface_manager.clone();
705            let verify_fut = async move {
706                let iface_manager = iface_manager.lock().await;
707                assert_eq!(iface_manager.ifaces, vec![0]);
708            };
709            let mut verify_fut = pin!(verify_fut);
710            assert_matches!(exec.run_until_stalled(&mut verify_fut), Poll::Ready(()));
711        }
712
713        // Verify that the IfaceRef was not updated.
714        assert!(listener.legacy_shim.get().is_err());
715    }
716
717    #[derive(Debug)]
718    struct FakePhyManager {
719        phys: Vec<u16>,
720        ifaces: Vec<u16>,
721        failed_phys: u32,
722        add_phy_succeeds: bool,
723        add_iface_succeeds: bool,
724    }
725
726    impl FakePhyManager {
727        fn new(add_phy_succeeds: bool, add_iface_succeeds: bool) -> Self {
728            FakePhyManager {
729                phys: Vec::new(),
730                ifaces: Vec::new(),
731                failed_phys: 0,
732                add_phy_succeeds,
733                add_iface_succeeds,
734            }
735        }
736    }
737
738    #[async_trait(?Send)]
739    impl PhyManagerApi for FakePhyManager {
740        async fn add_phy(&mut self, phy_id: u16) -> Result<(), PhyManagerError> {
741            if self.add_phy_succeeds {
742                self.phys.push(phy_id);
743                Ok(())
744            } else {
745                Err(PhyManagerError::PhyQueryFailure)
746            }
747        }
748
749        fn remove_phy(&mut self, phy_id: u16) {
750            self.phys.retain(|phy| *phy != phy_id)
751        }
752
753        async fn on_iface_added(&mut self, iface_id: u16) -> Result<(), PhyManagerError> {
754            if self.add_iface_succeeds {
755                self.ifaces.push(iface_id);
756                Ok(())
757            } else {
758                Err(PhyManagerError::IfaceQueryFailure)
759            }
760        }
761
762        fn on_iface_removed(&mut self, iface_id: u16) {
763            self.ifaces.retain(|iface| *iface != iface_id)
764        }
765
766        async fn create_all_client_ifaces(
767            &mut self,
768            _reason: CreateClientIfacesReason,
769        ) -> HashMap<u16, Result<Vec<u16>, PhyManagerError>> {
770            unimplemented!()
771        }
772
773        fn client_connections_enabled(&self) -> bool {
774            unimplemented!()
775        }
776
777        async fn destroy_all_client_ifaces(&mut self) -> Result<(), PhyManagerError> {
778            unimplemented!()
779        }
780
781        fn get_client(&mut self) -> Option<u16> {
782            unimplemented!();
783        }
784
785        async fn create_or_get_ap_iface(&mut self) -> Result<Option<u16>, PhyManagerError> {
786            unimplemented!();
787        }
788
789        async fn destroy_ap_iface(&mut self, _iface_id: u16) -> Result<(), PhyManagerError> {
790            unimplemented!();
791        }
792
793        async fn destroy_all_ap_ifaces(&mut self) -> Result<(), PhyManagerError> {
794            unimplemented!();
795        }
796
797        fn suggest_ap_mac(&mut self, _mac: MacAddr) {
798            unimplemented!()
799        }
800
801        fn get_phy_ids(&self) -> Vec<u16> {
802            unimplemented!()
803        }
804
805        fn log_phy_add_failure(&mut self) {
806            self.failed_phys += 1;
807        }
808
809        async fn set_country_code(
810            &mut self,
811            _country_code: Option<client_types::CountryCode>,
812        ) -> Result<(), PhyManagerError> {
813            unimplemented!();
814        }
815
816        fn record_defect(&mut self, _defect: Defect) {
817            unimplemented!();
818        }
819
820        async fn perform_recovery(&mut self, _summary: RecoverySummary) {
821            unimplemented!();
822        }
823
824        async fn on_before_suspend(&mut self) {}
825        async fn on_after_resume(&mut self) {}
826    }
827
828    #[derive(Debug)]
829    struct FakeIfaceManager {
830        ifaces: Vec<u16>,
831    }
832
833    impl FakeIfaceManager {
834        fn new() -> Self {
835            FakeIfaceManager { ifaces: Vec::new() }
836        }
837    }
838
839    #[async_trait(?Send)]
840    impl IfaceManagerApi for FakeIfaceManager {
841        async fn disconnect(
842            &mut self,
843            _network_id: client_types::NetworkIdentifier,
844            _reason: client_types::DisconnectReason,
845        ) -> Result<(), Error> {
846            unimplemented!();
847        }
848
849        async fn connect(&mut self, _connect_req: ConnectAttemptRequest) -> Result<(), Error> {
850            unimplemented!();
851        }
852
853        async fn record_idle_client(&mut self, _iface_id: u16) -> Result<(), Error> {
854            unimplemented!();
855        }
856
857        async fn has_idle_client(&mut self) -> Result<bool, Error> {
858            unimplemented!();
859        }
860
861        async fn handle_added_iface(&mut self, iface_id: u16) -> Result<(), Error> {
862            self.ifaces.push(iface_id);
863            Ok(())
864        }
865
866        async fn handle_removed_iface(&mut self, iface_id: u16) -> Result<(), Error> {
867            self.ifaces.retain(|iface| *iface != iface_id);
868            Ok(())
869        }
870
871        async fn get_sme_proxy_for_scan(&mut self) -> Result<SmeForScan, Error> {
872            unimplemented!()
873        }
874
875        async fn stop_client_connections(
876            &mut self,
877            _reason: client_types::DisconnectReason,
878        ) -> Result<(), Error> {
879            unimplemented!()
880        }
881
882        async fn start_client_connections(&mut self) -> Result<(), Error> {
883            unimplemented!()
884        }
885
886        async fn start_ap(
887            &mut self,
888            _config: ap_fsm::ApConfig,
889        ) -> Result<oneshot::Receiver<()>, Error> {
890            unimplemented!();
891        }
892
893        async fn stop_ap(
894            &mut self,
895            _ssid: ap_types::Ssid,
896            _password: Vec<u8>,
897        ) -> Result<(), Error> {
898            unimplemented!();
899        }
900
901        async fn stop_all_aps(&mut self) -> Result<(), Error> {
902            unimplemented!()
903        }
904
905        async fn set_country(
906            &mut self,
907            _country_code: Option<client_types::CountryCode>,
908        ) -> Result<(), Error> {
909            unimplemented!();
910        }
911    }
912
913    #[track_caller]
914    fn send_query_iface_response(
915        exec: &mut fasync::TestExecutor,
916        server: &mut fidl_service::DeviceMonitorRequestStream,
917        iface_info: Option<fidl_service::QueryIfaceResponse>,
918    ) {
919        let response = iface_info.as_ref().ok_or(zx::sys::ZX_ERR_NOT_FOUND);
920        assert_matches!(
921            exec.run_until_stalled(&mut server.next()),
922            Poll::Ready(Some(Ok(
923                fidl_service::DeviceMonitorRequest::QueryIface {
924                    iface_id: _,
925                    responder,
926                }
927            ))) => {
928                responder.send(response).expect("sending fake iface info");
929            }
930        );
931    }
932
933    #[fuchsia::test]
934    fn test_device_monitor_wake_leases() {
935        let mut exec = fasync::TestExecutor::new();
936        let test_values = test_setup(true, true);
937        let listener = Listener::new(
938            test_values.monitor_proxy,
939            IfaceRef::new(),
940            test_values.phy_manager.clone(),
941            test_values.iface_manager.clone(),
942            test_values.power_manager.clone(),
943        );
944
945        // 1. OnPhyAdded
946        let fut = handle_event(&listener, DeviceWatcherEvent::OnPhyAdded { phy_id: 0 });
947        let mut fut = pin!(fut);
948        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
949
950        // 2. OnPhyRemoved
951        let fut = handle_event(&listener, DeviceWatcherEvent::OnPhyRemoved { phy_id: 0 });
952        let mut fut = pin!(fut);
953        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
954
955        // 3. OnIfaceAdded
956        let mut monitor_stream = test_values.monitor_stream;
957        let fut = handle_event(&listener, DeviceWatcherEvent::OnIfaceAdded { iface_id: 0 });
958        let mut fut = pin!(fut);
959        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
960        send_query_iface_response(
961            &mut exec,
962            &mut monitor_stream,
963            Some(fidl_service::QueryIfaceResponse {
964                role: fidl_common::WlanMacRole::Client,
965                id: 0,
966                phy_id: 0,
967                phy_assigned_id: 0,
968                sta_addr: [0; 6],
969                factory_addr: [0; 6],
970            }),
971        );
972        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Pending);
973        assert_matches!(
974            exec.run_until_stalled(&mut monitor_stream.next()),
975            Poll::Ready(Some(Ok(fidl_service::DeviceMonitorRequest::GetClientSme {
976                iface_id: 0,
977                responder,
978                ..
979            }))) => {
980                responder.send(Ok(())).expect("sending get_client_sme response");
981            }
982        );
983        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
984
985        // 4. OnIfaceRemoved
986        let fut = handle_event(&listener, DeviceWatcherEvent::OnIfaceRemoved { iface_id: 0 });
987        let mut fut = pin!(fut);
988        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
989
990        // Verify that all device watcher wake leases were taken.
991        let calls = test_values.power_manager.calls.lock();
992        assert!(calls.contains(&"wlancfg-device-phy-added".to_string()));
993        assert!(calls.contains(&"wlancfg-device-phy-removed".to_string()));
994        assert!(calls.contains(&"wlancfg-device-iface-added".to_string()));
995        assert!(calls.contains(&"wlancfg-device-iface-removed".to_string()));
996    }
997}