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