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