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