wlancfg_lib/client/scan/
mod.rs

1// Copyright 2021 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
5//! Manages Scan requests for the Client Policy API.
6use crate::client::types;
7use crate::config_management::SavedNetworksManagerApi;
8use crate::mode_management::iface_manager_api::{IfaceManagerApi, SmeForScan};
9use crate::telemetry::{ScanEventInspectData, ScanIssue, TelemetryEvent, TelemetrySender};
10use anyhow::{Error, format_err};
11use async_trait::async_trait;
12use fuchsia_async::{self as fasync, DurationExt, TimeoutExt};
13use fuchsia_component::client::connect_to_protocol;
14use futures::channel::{mpsc, oneshot};
15use futures::future::{Fuse, FusedFuture, FutureExt};
16use futures::lock::Mutex;
17use futures::select;
18use futures::stream::{FuturesUnordered, StreamExt};
19use itertools::Itertools;
20use log::{debug, error, info, trace, warn};
21use std::collections::HashMap;
22use std::pin::pin;
23use std::sync::Arc;
24use {
25    fidl_fuchsia_location_sensor as fidl_location_sensor, fidl_fuchsia_wlan_common as fidl_common,
26    fidl_fuchsia_wlan_policy as fidl_policy, fidl_fuchsia_wlan_sme as fidl_sme,
27};
28
29mod fidl_conversion;
30mod queue;
31
32pub use fidl_conversion::{
33    scan_result_to_policy_scan_result, send_scan_error_over_fidl, send_scan_results_over_fidl,
34};
35
36// Delay between scanning retries when the firmware returns "ShouldWait" error code
37const SCAN_RETRY_DELAY_MS: i64 = 100;
38// Max time allowed for consumers of scan results to retrieve results
39const SCAN_CONSUMER_MAX_SECONDS_ALLOWED: i64 = 5;
40/// Capacity of "first come, first serve" slots available to scan requesters
41pub const SCAN_REQUEST_BUFFER_SIZE: usize = 100;
42
43// Inidication of the scan caller, for use in logging caller specific metrics
44#[derive(Debug, PartialEq)]
45pub enum ScanReason {
46    ClientRequest,
47    NetworkSelection,
48    BssSelection,
49    BssSelectionAugmentation,
50    RoamSearch,
51}
52
53#[async_trait(?Send)]
54pub trait ScanRequestApi {
55    async fn perform_scan(
56        &self,
57        scan_reason: ScanReason,
58        ssids: Vec<types::Ssid>,
59        channels: Vec<types::WlanChan>,
60    ) -> Result<Vec<types::ScanResult>, types::ScanError>;
61}
62
63pub struct ScanRequester {
64    pub sender: mpsc::Sender<ApiScanRequest>,
65}
66
67pub enum ApiScanRequest {
68    Scan(
69        ScanReason,
70        Vec<types::Ssid>,
71        Vec<types::WlanChan>,
72        oneshot::Sender<Result<Vec<types::ScanResult>, types::ScanError>>,
73    ),
74}
75
76#[async_trait(?Send)]
77impl ScanRequestApi for ScanRequester {
78    async fn perform_scan(
79        &self,
80        scan_reason: ScanReason,
81        ssids: Vec<types::Ssid>,
82        channels: Vec<types::WlanChan>,
83    ) -> Result<Vec<types::ScanResult>, types::ScanError> {
84        let (responder, receiver) = oneshot::channel();
85        self.sender
86            .clone()
87            .try_send(ApiScanRequest::Scan(scan_reason, ssids, channels, responder))
88            .map_err(|e| {
89                error!("Failed to send ScanRequest: {:?}", e);
90                types::ScanError::GeneralError
91            })?;
92        receiver.await.map_err(|e| {
93            error!("Failed to receive ScanRequest response: {:?}", e);
94            types::ScanError::GeneralError
95        })?
96    }
97}
98
99// Wrapper struct to track it the scan request is being retried.
100#[derive(Debug, Clone)]
101struct ScanRequest {
102    pub sme_req: fidl_sme::ScanRequest,
103    pub is_retry: bool,
104}
105impl From<fidl_sme::ScanRequest> for ScanRequest {
106    fn from(sme_req: fidl_sme::ScanRequest) -> Self {
107        Self { sme_req, is_retry: false }
108    }
109}
110
111/// Create a future representing the scan manager loop.
112pub async fn serve_scanning_loop(
113    iface_manager: Arc<Mutex<dyn IfaceManagerApi>>,
114    saved_networks_manager: Arc<dyn SavedNetworksManagerApi>,
115    telemetry_sender: TelemetrySender,
116    location_sensor_updater: impl ScanResultUpdate,
117    mut scan_request_channel: mpsc::Receiver<ApiScanRequest>,
118) -> Result<(), Error> {
119    let mut queue = queue::RequestQueue::new(telemetry_sender.clone());
120    let mut location_sensor_updates = FuturesUnordered::new();
121    // Use `Fuse::terminated()` to create an already-terminated future
122    // which may be instantiated later.
123    let ongoing_scan = Fuse::terminated();
124    let mut ongoing_scan = pin!(ongoing_scan);
125
126    let transform_next_sme_req = |next_sme_req: Option<ScanRequest>| match next_sme_req {
127        None => Fuse::terminated(),
128        Some(next_sme_req) => perform_scan(
129            next_sme_req,
130            iface_manager.clone(),
131            saved_networks_manager.clone(),
132            telemetry_sender.clone(),
133        )
134        .fuse(),
135    };
136
137    loop {
138        select! {
139            request = scan_request_channel.next() => {
140                match request {
141                    Some(ApiScanRequest::Scan(reason, ssids, channels, responder)) => {
142                        queue.add_request(reason, ssids, channels, responder, zx::MonotonicInstant::get());
143                        // Check if there's an ongoing scan, otherwise take one from the queue
144                        if ongoing_scan.is_terminated() {
145                            ongoing_scan.set(transform_next_sme_req(queue.get_next_sme_request().map(|req| req.into())));
146                        }
147                    },
148                    None => {
149                        error!("Unexpected 'None' on scan_request_channel");
150                    }
151                }
152            },
153            (completed_sme_request, scan_results) = ongoing_scan => {
154                if scan_results == Err(types::ScanError::Cancelled) && !completed_sme_request.is_retry {
155                    // Retry after delay on first cancellation attempt.
156                    info!("Driver requested a delay before retrying the cancelled scan request.");
157                    fasync::Timer::new(zx::MonotonicDuration::from_millis(SCAN_RETRY_DELAY_MS).after_now()).await;
158                    ongoing_scan.set(transform_next_sme_req(Some(ScanRequest {is_retry: true, ..completed_sme_request})));
159                    continue;
160                }
161                match scan_results {
162                    Ok(ref results) => {
163                        // Return results to requester.
164                        queue.handle_completed_sme_scan(
165                            completed_sme_request.sme_req.clone(),
166                            scan_results.clone(),
167                            zx::MonotonicInstant::get()
168                        );
169                        // Send scan results to Location
170                        if !results.is_empty() {
171                            location_sensor_updates.push(location_sensor_updater
172                                .update_scan_results(results.clone())
173                                .on_timeout(zx::MonotonicDuration::from_seconds(SCAN_CONSUMER_MAX_SECONDS_ALLOWED), || {
174                                    error!("Timed out waiting for location sensor to get results");
175                                })
176                            );
177                        }
178                    },
179                    Err(error) => {
180                        // Handle all other cases (including cancellation after retry). Return
181                        // results immediately.
182                        queue.handle_completed_sme_scan(
183                            completed_sme_request.sme_req.clone(),
184                            scan_results.clone(),
185                            zx::MonotonicInstant::get()
186                        );
187                        // If there was a cancellation after retrying, add a back off.
188                        if error == types::ScanError::Cancelled {
189                            info!("After multiple cancelled attempts, driver requested a delay before serving new scan requests.");
190                            fasync::Timer::new(zx::MonotonicDuration::from_millis(SCAN_RETRY_DELAY_MS).after_now()).await;
191                        }
192                    }
193                }
194                // Fetch the next request
195                ongoing_scan.set(transform_next_sme_req(
196                    queue.get_next_sme_request().map(|req| req.into())
197                ));
198            },
199            () = location_sensor_updates.select_next_some() => {},
200            complete => {
201                // all futures are terminated
202                warn!("Unexpectedly reached end of scanning loop");
203                break
204            },
205        }
206    }
207
208    Err(format_err!("Unexpectedly reached end of scanning loop"))
209}
210
211/// Allows for consumption of updated scan results.
212#[async_trait(?Send)]
213pub trait ScanResultUpdate {
214    async fn update_scan_results(&self, scan_results: Vec<types::ScanResult>);
215}
216
217/// Requests a new SME scan and returns the results.
218async fn sme_scan(
219    sme_proxy: &SmeForScan,
220    scan_request: &fidl_sme::ScanRequest,
221    scan_defects: &mut Vec<ScanIssue>,
222) -> Result<Vec<wlan_common::scan::ScanResult>, types::ScanError> {
223    debug!("Sending scan request to SME");
224    let scan_result = sme_proxy.scan(scan_request).await.map_err(|error| {
225        error!("Failed to send scan to SME: {:?}", error);
226        types::ScanError::GeneralError
227    })?;
228    debug!("Finished getting scan results from SME");
229    match scan_result {
230        Ok(vmo) => {
231            let scan_result_list = wlan_common::scan::read_vmo(vmo).map_err(|error| {
232                error!("Failed to read scan results from VMO: {:?}", error);
233                types::ScanError::GeneralError
234            })?;
235            Ok(scan_result_list
236                .into_iter()
237                .filter_map(|scan_result| {
238                    wlan_common::scan::ScanResult::try_from(scan_result).map(Some).unwrap_or_else(
239                        |e| {
240                            // TODO(https://fxbug.dev/42164415): Report details about which
241                            // scan result failed to convert if possible.
242                            error!("ScanResult conversion failed: {:?}", e);
243                            None
244                        },
245                    )
246                })
247                .inspect(|scan_result| {
248                    // This trace-level logging is only enabled when a user manually sets the log
249                    // level to TRACE with `fx log` or `fx test`.
250                    trace!(
251                        "Scan result SSID: {}, BSSID: {}, channel: {}",
252                        scan_result.bss_description.ssid,
253                        scan_result.bss_description.bssid,
254                        scan_result.bss_description.channel
255                    )
256                })
257                .collect::<Vec<_>>())
258        }
259        Err(scan_error_code) => {
260            log_metric_for_scan_error(&scan_error_code, scan_defects);
261            match scan_error_code {
262                fidl_sme::ScanErrorCode::ShouldWait
263                | fidl_sme::ScanErrorCode::CanceledByDriverOrFirmware => {
264                    info!("Scan cancelled by SME, retry indicated: {:?}", scan_error_code);
265                    Err(types::ScanError::Cancelled)
266                }
267                _ => {
268                    error!("Scan error from SME: {:?}", scan_error_code);
269                    Err(types::ScanError::GeneralError)
270                }
271            }
272        }
273    }
274}
275
276/// Handles incoming scan requests by creating a new SME scan request.
277async fn perform_scan(
278    scan_request: ScanRequest,
279    iface_manager: Arc<Mutex<dyn IfaceManagerApi>>,
280    saved_networks_manager: Arc<dyn SavedNetworksManagerApi>,
281    telemetry_sender: TelemetrySender,
282) -> (ScanRequest, Result<Vec<types::ScanResult>, types::ScanError>) {
283    let bss_by_network: HashMap<types::NetworkIdentifierDetailed, Vec<types::Bss>>;
284    let mut scan_event_inspect_data = ScanEventInspectData::new();
285    let mut scan_defects: Vec<ScanIssue> = vec![];
286
287    let sme_proxy = match iface_manager.lock().await.get_sme_proxy_for_scan().await {
288        Ok(proxy) => proxy,
289        Err(_) => {
290            warn!("Failed to get sme proxy for passive scan");
291            return (scan_request, Err(types::ScanError::GeneralError));
292        }
293    };
294    let scan_results = sme_scan(&sme_proxy, &scan_request.sme_req, &mut scan_defects).await;
295    report_scan_defects_to_sme(&sme_proxy, &scan_results, &scan_request.sme_req).await;
296
297    match scan_results {
298        Ok(results) => {
299            // Record observed BSSs to saved networks manager.
300            let target_ssids = match scan_request.sme_req {
301                fidl_sme::ScanRequest::Passive(_) => vec![],
302                fidl_sme::ScanRequest::Active(ref req) => req
303                    .ssids
304                    .iter()
305                    .map(|s| types::Ssid::from_bytes_unchecked(s.to_vec()))
306                    .collect(),
307            };
308            bss_by_network =
309                bss_to_network_map(results, &target_ssids, &mut scan_event_inspect_data);
310            saved_networks_manager.record_scan_result(target_ssids, &bss_by_network).await;
311        }
312        Err(scan_err) => {
313            return (scan_request, Err(scan_err));
314        }
315    }
316
317    // If the passive scan results are empty, report an empty scan results metric.
318    if let fidl_sme::ScanRequest::Passive(_) = scan_request.sme_req
319        && bss_by_network.is_empty()
320    {
321        scan_defects.push(ScanIssue::EmptyScanResults);
322    }
323
324    telemetry_sender
325        .send(TelemetryEvent::ScanEvent { inspect_data: scan_event_inspect_data, scan_defects });
326
327    let scan_results = network_map_to_scan_result(bss_by_network);
328    (scan_request, Ok(scan_results))
329}
330
331/// The location sensor module uses scan results to help determine the
332/// device's location, for use by the Emergency Location Provider.
333pub struct LocationSensorUpdater {}
334#[async_trait(?Send)]
335impl ScanResultUpdate for LocationSensorUpdater {
336    async fn update_scan_results(&self, scan_results: Vec<types::ScanResult>) {
337        async fn send_results(scan_results: Vec<fidl_policy::ScanResult>) -> Result<(), Error> {
338            // Get an output iterator
339            let (iter, server) =
340                fidl::endpoints::create_endpoints::<fidl_policy::ScanResultIteratorMarker>();
341            let location_watcher_proxy =
342                connect_to_protocol::<fidl_location_sensor::WlanBaseStationWatcherMarker>()
343                    .map_err(|err| {
344                        format_err!("failed to connect to location sensor service: {:?}", err)
345                    })?;
346            location_watcher_proxy
347                .report_current_stations(iter)
348                .map_err(|err| format_err!("failed to call location sensor service: {:?}", err))?;
349
350            // Send results to the iterator
351            fidl_conversion::send_scan_results_over_fidl(server, &scan_results).await
352        }
353
354        // Set "wpa3_supported: true" such that scan results are not artificially modified to hide
355        // WPA3 networks.
356        let scan_results = fidl_conversion::scan_result_to_policy_scan_result(&scan_results, true);
357        // Filter out any errors and just log a message.
358        // No error recovery, we'll just try again next time a scan result comes in.
359        if let Err(e) = send_results(scan_results).await {
360            info!("Failed to send scan results to location sensor: {:?}", e)
361        } else {
362            debug!("Updated location sensor")
363        };
364    }
365}
366
367/// Converts sme::ScanResult to our internal BSS type, then adds it to a map.
368/// Only keeps the first unique instance of a BSSID
369fn bss_to_network_map(
370    scan_result_list: Vec<wlan_common::scan::ScanResult>,
371    target_ssids: &[types::Ssid],
372    scan_event_inspect_data: &mut ScanEventInspectData,
373) -> HashMap<types::NetworkIdentifierDetailed, Vec<types::Bss>> {
374    let mut bss_by_network: HashMap<types::NetworkIdentifierDetailed, Vec<types::Bss>> =
375        HashMap::new();
376    for scan_result in scan_result_list.into_iter() {
377        let security_type: types::SecurityTypeDetailed =
378            scan_result.bss_description.protection().into();
379        if security_type == types::SecurityTypeDetailed::Unknown {
380            // Log a space-efficient version of the IEs.
381            let readable_ie =
382                scan_result.bss_description.ies().iter().map(|n| n.to_string()).join(",");
383            debug!("Encountered unknown protection, ies: [{:?}]", readable_ie.clone());
384            scan_event_inspect_data.unknown_protection_ies.push(readable_ie);
385        };
386        let entry = bss_by_network
387            .entry(types::NetworkIdentifierDetailed {
388                ssid: scan_result.bss_description.ssid.clone(),
389                security_type,
390            })
391            .or_default();
392
393        // Check if this BSSID is already in the hashmap
394        if !entry.iter().any(|existing_bss| existing_bss.bssid == scan_result.bss_description.bssid)
395        {
396            entry.push(types::Bss {
397                bssid: scan_result.bss_description.bssid,
398                signal: types::Signal {
399                    rssi_dbm: scan_result.bss_description.rssi_dbm,
400                    snr_db: scan_result.bss_description.snr_db,
401                },
402                channel: scan_result.bss_description.channel,
403                timestamp: scan_result.timestamp,
404                // TODO(123709): if target_ssids contains the wildcard, this need to be "Unknown"
405                observation: if target_ssids.contains(&scan_result.bss_description.ssid) {
406                    types::ScanObservation::Active
407                } else {
408                    types::ScanObservation::Passive
409                },
410                compatibility: scan_result.compatibility,
411                bss_description: wlan_common::sequestered::Sequestered::from(
412                    fidl_common::BssDescription::from(scan_result.bss_description),
413                ),
414            });
415        };
416    }
417    bss_by_network
418}
419
420fn network_map_to_scan_result(
421    mut bss_by_network: HashMap<types::NetworkIdentifierDetailed, Vec<types::Bss>>,
422) -> Vec<types::ScanResult> {
423    let mut scan_results: Vec<types::ScanResult> = bss_by_network
424        .drain()
425        .map(|(types::NetworkIdentifierDetailed { ssid, security_type }, bss_entries)| {
426            let compatibility = if bss_entries.iter().any(|bss| bss.is_compatible()) {
427                fidl_policy::Compatibility::Supported
428            } else {
429                fidl_policy::Compatibility::DisallowedNotSupported
430            };
431            types::ScanResult {
432                ssid,
433                security_type_detailed: security_type,
434                entries: bss_entries,
435                compatibility,
436            }
437        })
438        .collect();
439
440    scan_results.sort_by(|a, b| a.ssid.cmp(&b.ssid));
441    scan_results
442}
443
444fn log_metric_for_scan_error(reason: &fidl_sme::ScanErrorCode, scan_defects: &mut Vec<ScanIssue>) {
445    let metric_type = match *reason {
446        fidl_sme::ScanErrorCode::NotSupported
447        | fidl_sme::ScanErrorCode::InternalError
448        | fidl_sme::ScanErrorCode::InternalMlmeError => ScanIssue::ScanFailure,
449        fidl_sme::ScanErrorCode::ShouldWait
450        | fidl_sme::ScanErrorCode::CanceledByDriverOrFirmware => ScanIssue::AbortedScan,
451    };
452
453    scan_defects.push(metric_type);
454}
455
456async fn report_scan_defects_to_sme(
457    sme_proxy: &SmeForScan,
458    scan_result: &Result<Vec<wlan_common::scan::ScanResult>, types::ScanError>,
459    scan_request: &fidl_sme::ScanRequest,
460) {
461    match scan_result {
462        Ok(results) => {
463            // If passive scan results are empty, report an empty scan results metric and defect.
464            if results.is_empty()
465                && let fidl_sme::ScanRequest::Passive(_) = scan_request
466            {
467                sme_proxy.log_empty_scan_defect();
468            }
469        }
470        Err(types::ScanError::GeneralError) => sme_proxy.log_failed_scan_defect(),
471        Err(types::ScanError::Cancelled) => sme_proxy.log_aborted_scan_defect(),
472    }
473}
474
475#[cfg(test)]
476mod tests {
477    use super::*;
478    use crate::access_point::state_machine as ap_fsm;
479    use crate::mode_management::iface_manager_api::ConnectAttemptRequest;
480    use crate::mode_management::{Defect, IfaceFailure};
481    use crate::util::testing::fakes::FakeSavedNetworksManager;
482    use crate::util::testing::{
483        generate_channel, generate_random_sme_scan_result, run_until_completion,
484    };
485    use assert_matches::assert_matches;
486    use fidl::endpoints::{ControlHandle, Responder, create_proxy};
487    use futures::future;
488    use futures::task::Poll;
489    use std::pin::pin;
490    use test_case::test_case;
491    use wlan_common::ie::IeType;
492    use wlan_common::scan::{Compatible, Incompatible, write_vmo};
493    use wlan_common::security::SecurityDescriptor;
494    use wlan_common::test_utils::fake_frames::fake_unknown_rsne;
495    use wlan_common::test_utils::fake_stas::IesOverrides;
496    use wlan_common::{fake_bss_description, random_fidl_bss_description};
497    use {fidl_fuchsia_wlan_common_security as fidl_security, fuchsia_async as fasync};
498
499    fn active_sme_req(ssids: Vec<&str>, channels: Vec<u8>) -> fidl_sme::ScanRequest {
500        fidl_sme::ScanRequest::Active(fidl_sme::ActiveScanRequest {
501            ssids: ssids.iter().map(|s| s.as_bytes().to_vec()).collect(),
502            channels,
503        })
504    }
505
506    fn passive_sme_req() -> fidl_sme::ScanRequest {
507        fidl_sme::ScanRequest::Passive(fidl_sme::PassiveScanRequest {})
508    }
509
510    struct FakeIfaceManager {
511        pub sme_proxy: fidl_fuchsia_wlan_sme::ClientSmeProxy,
512        pub defect_sender: mpsc::Sender<Defect>,
513        pub defect_receiver: mpsc::Receiver<Defect>,
514    }
515
516    impl FakeIfaceManager {
517        pub fn new(proxy: fidl_fuchsia_wlan_sme::ClientSmeProxy) -> Self {
518            let (defect_sender, defect_receiver) = mpsc::channel(100);
519            FakeIfaceManager { sme_proxy: proxy, defect_sender, defect_receiver }
520        }
521    }
522
523    #[async_trait(?Send)]
524    impl IfaceManagerApi for FakeIfaceManager {
525        async fn disconnect(
526            &mut self,
527            _network_id: types::NetworkIdentifier,
528            _reason: types::DisconnectReason,
529        ) -> Result<(), Error> {
530            unimplemented!()
531        }
532
533        async fn connect(&mut self, _connect_req: ConnectAttemptRequest) -> Result<(), Error> {
534            unimplemented!()
535        }
536
537        async fn record_idle_client(&mut self, _iface_id: u16) -> Result<(), Error> {
538            unimplemented!()
539        }
540
541        async fn has_idle_client(&mut self) -> Result<bool, Error> {
542            unimplemented!()
543        }
544
545        async fn handle_added_iface(&mut self, _iface_id: u16) -> Result<(), Error> {
546            unimplemented!()
547        }
548
549        async fn handle_removed_iface(&mut self, _iface_id: u16) -> Result<(), Error> {
550            unimplemented!()
551        }
552
553        async fn get_sme_proxy_for_scan(&mut self) -> Result<SmeForScan, Error> {
554            Ok(SmeForScan::new(self.sme_proxy.clone(), 0, self.defect_sender.clone()))
555        }
556
557        async fn stop_client_connections(
558            &mut self,
559            _reason: types::DisconnectReason,
560        ) -> Result<(), Error> {
561            unimplemented!()
562        }
563
564        async fn start_client_connections(&mut self) -> Result<(), Error> {
565            unimplemented!()
566        }
567
568        async fn start_ap(
569            &mut self,
570            _config: ap_fsm::ApConfig,
571        ) -> Result<oneshot::Receiver<()>, Error> {
572            unimplemented!()
573        }
574
575        async fn stop_ap(&mut self, _ssid: types::Ssid, _password: Vec<u8>) -> Result<(), Error> {
576            unimplemented!()
577        }
578
579        async fn stop_all_aps(&mut self) -> Result<(), Error> {
580            unimplemented!()
581        }
582
583        async fn set_country(
584            &mut self,
585            _country_code: Option<types::CountryCode>,
586        ) -> Result<(), Error> {
587            unimplemented!()
588        }
589    }
590
591    /// Creates a Client wrapper.
592    async fn create_iface_manager()
593    -> (Arc<Mutex<FakeIfaceManager>>, fidl_sme::ClientSmeRequestStream) {
594        let (client_sme, remote) = create_proxy::<fidl_sme::ClientSmeMarker>();
595        let iface_manager = FakeIfaceManager::new(client_sme);
596        let iface_manager = Arc::new(Mutex::new(iface_manager));
597        (iface_manager, remote.into_stream())
598    }
599
600    /// Creates an SME proxy for tests.
601    async fn create_sme_proxy() -> (fidl_sme::ClientSmeProxy, fidl_sme::ClientSmeRequestStream) {
602        let (client_sme, remote) = create_proxy::<fidl_sme::ClientSmeMarker>();
603        (client_sme, remote.into_stream())
604    }
605
606    struct MockScanResultConsumer {
607        scan_results: Arc<Mutex<Option<Vec<types::ScanResult>>>>,
608        stalled: Arc<Mutex<bool>>,
609    }
610    impl MockScanResultConsumer {
611        #[allow(clippy::type_complexity)]
612        fn new() -> (Self, Arc<Mutex<Option<Vec<types::ScanResult>>>>, Arc<Mutex<bool>>) {
613            let scan_results = Arc::new(Mutex::new(None));
614            let stalled = Arc::new(Mutex::new(false));
615            (
616                Self { scan_results: scan_results.clone(), stalled: stalled.clone() },
617                scan_results,
618                stalled,
619            )
620        }
621    }
622    #[async_trait(?Send)]
623    impl ScanResultUpdate for MockScanResultConsumer {
624        async fn update_scan_results(&self, scan_results: Vec<types::ScanResult>) {
625            if *self.stalled.lock().await {
626                let () = future::pending().await;
627                unreachable!();
628            }
629            let mut guard = self.scan_results.lock().await;
630            *guard = Some(scan_results);
631        }
632    }
633
634    // Creates test data for the scan functions.
635    struct MockScanData {
636        sme_results: Vec<fidl_sme::ScanResult>,
637        internal_results: Vec<types::ScanResult>,
638    }
639    fn create_scan_ap_data(observation: types::ScanObservation) -> MockScanData {
640        let sme_result_1 = fidl_sme::ScanResult {
641            compatibility: fidl_sme::Compatibility::Compatible(fidl_sme::Compatible {
642                mutual_security_protocols: vec![fidl_security::Protocol::Wpa3Personal],
643            }),
644            timestamp_nanos: zx::MonotonicInstant::get().into_nanos(),
645            bss_description: random_fidl_bss_description!(
646                Wpa3,
647                bssid: [0, 0, 0, 0, 0, 0],
648                ssid: types::Ssid::try_from("duplicated ssid").unwrap(),
649                rssi_dbm: 0,
650                snr_db: 1,
651                channel: types::WlanChan::new(1, types::Cbw::Cbw20),
652            ),
653        };
654        let sme_result_2 = fidl_sme::ScanResult {
655            compatibility: fidl_sme::Compatibility::Compatible(fidl_sme::Compatible {
656                mutual_security_protocols: vec![fidl_security::Protocol::Wpa2Personal],
657            }),
658            timestamp_nanos: zx::MonotonicInstant::get().into_nanos(),
659            bss_description: random_fidl_bss_description!(
660                Wpa2,
661                bssid: [1, 2, 3, 4, 5, 6],
662                ssid: types::Ssid::try_from("unique ssid").unwrap(),
663                rssi_dbm: 7,
664                snr_db: 2,
665                channel: types::WlanChan::new(8, types::Cbw::Cbw20),
666            ),
667        };
668        let sme_result_3 = fidl_sme::ScanResult {
669            compatibility: fidl_sme::Compatibility::Incompatible(fidl_sme::Incompatible {
670                description: String::from("unknown"),
671                disjoint_security_protocols: None,
672            }),
673            timestamp_nanos: zx::MonotonicInstant::get().into_nanos(),
674            bss_description: random_fidl_bss_description!(
675                Wpa3,
676                bssid: [7, 8, 9, 10, 11, 12],
677                ssid: types::Ssid::try_from("duplicated ssid").unwrap(),
678                rssi_dbm: 13,
679                snr_db: 3,
680                channel: types::WlanChan::new(11, types::Cbw::Cbw20),
681            ),
682        };
683
684        let sme_results = vec![sme_result_1.clone(), sme_result_2.clone(), sme_result_3.clone()];
685        // input_aps contains some duplicate SSIDs, which should be
686        // grouped in the output.
687        let internal_results = vec![
688            types::ScanResult {
689                ssid: types::Ssid::try_from("duplicated ssid").unwrap(),
690                security_type_detailed: types::SecurityTypeDetailed::Wpa3Personal,
691                entries: vec![
692                    types::Bss {
693                        bssid: types::Bssid::from([0, 0, 0, 0, 0, 0]),
694                        signal: types::Signal { rssi_dbm: 0, snr_db: 1 },
695                        timestamp: zx::MonotonicInstant::from_nanos(sme_result_1.timestamp_nanos),
696                        channel: types::WlanChan::new(1, types::Cbw::Cbw20),
697                        observation,
698                        compatibility: Compatible::expect_ok([SecurityDescriptor::WPA3_PERSONAL]),
699                        bss_description: sme_result_1.bss_description.clone().into(),
700                    },
701                    types::Bss {
702                        bssid: types::Bssid::from([7, 8, 9, 10, 11, 12]),
703                        signal: types::Signal { rssi_dbm: 13, snr_db: 3 },
704                        timestamp: zx::MonotonicInstant::from_nanos(sme_result_3.timestamp_nanos),
705                        channel: types::WlanChan::new(11, types::Cbw::Cbw20),
706                        observation,
707                        compatibility: Incompatible::unknown(),
708                        bss_description: sme_result_3.bss_description.clone().into(),
709                    },
710                ],
711                compatibility: types::Compatibility::Supported,
712            },
713            types::ScanResult {
714                ssid: types::Ssid::try_from("unique ssid").unwrap(),
715                security_type_detailed: types::SecurityTypeDetailed::Wpa2Personal,
716                entries: vec![types::Bss {
717                    bssid: types::Bssid::from([1, 2, 3, 4, 5, 6]),
718                    signal: types::Signal { rssi_dbm: 7, snr_db: 2 },
719                    timestamp: zx::MonotonicInstant::from_nanos(sme_result_2.timestamp_nanos),
720                    channel: types::WlanChan::new(8, types::Cbw::Cbw20),
721                    observation,
722                    compatibility: Compatible::expect_ok([SecurityDescriptor::WPA2_PERSONAL]),
723                    bss_description: sme_result_2.bss_description.clone().into(),
724                }],
725                compatibility: types::Compatibility::Supported,
726            },
727        ];
728
729        MockScanData { sme_results, internal_results }
730    }
731
732    fn create_telemetry_sender_and_receiver() -> (TelemetrySender, mpsc::Receiver<TelemetryEvent>) {
733        let (sender, receiver) = mpsc::channel::<TelemetryEvent>(100);
734        let sender = TelemetrySender::new(sender);
735        (sender, receiver)
736    }
737
738    fn get_fake_defects(
739        exec: &mut fasync::TestExecutor,
740        iface_manager: Arc<Mutex<FakeIfaceManager>>,
741    ) -> Vec<Defect> {
742        let defects_fut = async move {
743            let mut iface_manager = iface_manager.lock().await;
744            let mut defects = Vec::<Defect>::new();
745            while let Ok(Some(defect)) = iface_manager.defect_receiver.try_next() {
746                defects.push(defect)
747            }
748
749            defects
750        };
751        let mut defects_fut = pin!(defects_fut);
752        assert_matches!(exec.run_until_stalled(&mut defects_fut), Poll::Ready(defects) => defects)
753    }
754
755    #[fuchsia::test]
756    fn sme_scan_with_passive_request() {
757        let mut exec = fasync::TestExecutor::new();
758        let (sme_proxy, mut sme_stream) = exec.run_singlethreaded(create_sme_proxy());
759        let (defect_sender, _) = mpsc::channel(100);
760        let sme_proxy = SmeForScan::new(sme_proxy, 0, defect_sender);
761
762        // Issue request to scan.
763        let scan_request = fidl_sme::ScanRequest::Passive(fidl_sme::PassiveScanRequest {});
764        let mut scan_defects = vec![];
765        let scan_fut = sme_scan(&sme_proxy, &scan_request, &mut scan_defects);
766        let mut scan_fut = pin!(scan_fut);
767
768        // Request scan data from SME
769        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Pending);
770
771        // Create mock scan data
772        let MockScanData { sme_results: input_aps, internal_results: _ } =
773            create_scan_ap_data(types::ScanObservation::Passive);
774        // Validate the SME received the scan_request and send back mock data
775        assert_matches!(
776            exec.run_until_stalled(&mut sme_stream.next()),
777            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan {
778                req, responder,
779            }))) => {
780                assert_eq!(req, scan_request);
781                let vmo = write_vmo(input_aps.clone()).expect("failed to write VMO");
782                responder.send(Ok(vmo)).expect("failed to send scan data");
783            }
784        );
785
786        // Check for results
787        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Ready(result) => {
788            let scan_results: Vec<fidl_sme::ScanResult> = result.expect("failed to get scan results")
789                .iter().map(|r| r.clone().into()).collect();
790            assert_eq!(scan_results, input_aps);
791        });
792
793        // No further requests to the sme
794        assert_matches!(exec.run_until_stalled(&mut sme_stream.next()), Poll::Pending);
795    }
796
797    #[fuchsia::test]
798    fn sme_scan_with_active_request() {
799        let mut exec = fasync::TestExecutor::new();
800        let (sme_proxy, mut sme_stream) = exec.run_singlethreaded(create_sme_proxy());
801        let (defect_sender, _) = mpsc::channel(100);
802        let sme_proxy = SmeForScan::new(sme_proxy, 0, defect_sender);
803
804        // Issue request to scan.
805        let scan_request = fidl_sme::ScanRequest::Active(fidl_sme::ActiveScanRequest {
806            ssids: vec![
807                types::Ssid::try_from("foo_ssid").unwrap().into(),
808                types::Ssid::try_from("bar_ssid").unwrap().into(),
809            ],
810            channels: vec![1, 20],
811        });
812        let mut scan_defects = vec![];
813        let scan_fut = sme_scan(&sme_proxy, &scan_request, &mut scan_defects);
814        let mut scan_fut = pin!(scan_fut);
815
816        // Request scan data from SME
817        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Pending);
818
819        // Create mock scan data
820        let MockScanData { sme_results: input_aps, internal_results: _ } =
821            create_scan_ap_data(types::ScanObservation::Active);
822        // Validate the SME received the scan_request and send back mock data
823        assert_matches!(
824            exec.run_until_stalled(&mut sme_stream.next()),
825            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan {
826                req, responder,
827            }))) => {
828                assert_eq!(req, scan_request);
829                let vmo = write_vmo(input_aps.clone()).expect("failed to write VMO");
830                responder.send(Ok(vmo)).expect("failed to send scan data");
831            }
832        );
833
834        // Check for results
835        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Ready(result) => {
836            let scan_results: Vec<fidl_sme::ScanResult> = result.expect("failed to get scan results")
837                .iter().map(|r| r.clone().into()).collect();
838            assert_eq!(scan_results, input_aps);
839        });
840
841        // No further requests to the sme
842        assert_matches!(exec.run_until_stalled(&mut sme_stream.next()), Poll::Pending);
843    }
844
845    #[fuchsia::test]
846    fn sme_channel_closed_while_awaiting_scan_results() {
847        let mut exec = fasync::TestExecutor::new();
848        let (sme_proxy, mut sme_stream) = exec.run_singlethreaded(create_sme_proxy());
849        let (defect_sender, _) = mpsc::channel(100);
850        let sme_proxy = SmeForScan::new(sme_proxy, 0, defect_sender);
851
852        // Issue request to scan.
853        let scan_request = fidl_sme::ScanRequest::Passive(fidl_sme::PassiveScanRequest {});
854        let mut scan_defects = vec![];
855        let scan_fut = sme_scan(&sme_proxy, &scan_request, &mut scan_defects);
856        let mut scan_fut = pin!(scan_fut);
857
858        // Request scan data from SME
859        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Pending);
860
861        // Check that a scan request was sent to the sme and close the channel
862        assert_matches!(
863            exec.run_until_stalled(&mut sme_stream.next()),
864            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan {
865                req: _, responder,
866            }))) => {
867                // Shutdown SME request stream.
868                responder.control_handle().shutdown();
869                // TODO(https://fxbug.dev/42161447): Drop the stream to shutdown the channel.
870                drop(sme_stream);
871            }
872        );
873
874        // Check for results
875        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Ready(result) => {
876            let error = result.expect_err("did not expect scan results");
877            assert_eq!(error, types::ScanError::GeneralError);
878        });
879    }
880
881    #[fuchsia::test]
882    fn basic_scan() {
883        let mut exec = fasync::TestExecutor::new();
884        let (client, mut sme_stream) = exec.run_singlethreaded(create_iface_manager());
885        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
886        let (telemetry_sender, mut telemetry_receiver) = create_telemetry_sender_and_receiver();
887        // Issue request to scan.
888        let sme_scan = passive_sme_req();
889        let scan_fut =
890            perform_scan(sme_scan.clone().into(), client, saved_networks_manager, telemetry_sender);
891        let mut scan_fut = pin!(scan_fut);
892
893        // Progress scan handler forward so that it will respond to the iterator get next request.
894        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Pending);
895
896        // Create mock scan data and send it via the SME
897        let MockScanData { sme_results: input_aps, internal_results: internal_aps } =
898            create_scan_ap_data(types::ScanObservation::Passive);
899        assert_matches!(
900            exec.run_until_stalled(&mut sme_stream.next()),
901            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan {
902                req, responder,
903            }))) => {
904                assert_eq!(req, sme_scan.clone());
905                let vmo = write_vmo(input_aps).expect("failed to write VMO");
906                responder.send(Ok(vmo)).expect("failed to send scan data");
907            }
908        );
909
910        // Process scan handler
911        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Ready((request, results)) => {
912            assert_eq!(request.sme_req, sme_scan);
913            assert_eq!(results.unwrap(), internal_aps);
914        });
915
916        // Since the scanning process went off without a hitch, there should not be any defect
917        // metrics logged.
918        assert_matches!(
919            telemetry_receiver.try_next(),
920            Ok(Some(TelemetryEvent::ScanEvent {inspect_data, scan_defects})) => {
921                assert_eq!(inspect_data, ScanEventInspectData::new());
922                assert_eq!(scan_defects, vec![]);
923        });
924    }
925
926    #[fuchsia::test]
927    fn empty_passive_scan_results() {
928        let mut exec = fasync::TestExecutor::new();
929        let (client, mut sme_stream) = exec.run_singlethreaded(create_iface_manager());
930        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
931        let (telemetry_sender, mut telemetry_receiver) = create_telemetry_sender_and_receiver();
932
933        // Issue request to scan.
934        let sme_scan = passive_sme_req();
935        let scan_fut = perform_scan(
936            sme_scan.clone().into(),
937            client.clone(),
938            saved_networks_manager,
939            telemetry_sender,
940        );
941        let mut scan_fut = pin!(scan_fut);
942
943        // Progress scan handler
944        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Pending);
945
946        // Send back empty scan results via the SME
947        assert_matches!(
948            exec.run_until_stalled(&mut sme_stream.next()),
949            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan {
950                req, responder,
951            }))) => {
952                assert_eq!(req, sme_scan.clone());
953                let vmo = write_vmo(vec![]).expect("failed to write VMO");
954                responder.send(Ok(vmo)).expect("failed to send scan data");
955            }
956        );
957
958        // Process response from SME (which is empty) and expect the future to complete.
959        assert_matches!(exec.run_until_stalled(&mut scan_fut),  Poll::Ready((request, results)) => {
960            assert_eq!(request.sme_req, sme_scan);
961            assert!(results.unwrap().is_empty());
962        });
963
964        // Verify that an empty scan result has been logged
965        assert_matches!(
966            telemetry_receiver.try_next(),
967            Ok(Some(TelemetryEvent::ScanEvent {inspect_data, scan_defects})) => {
968                assert_eq!(inspect_data, ScanEventInspectData::new());
969                assert_eq!(scan_defects, vec![ScanIssue::EmptyScanResults]);
970        });
971
972        // Verify that a defect was logged.
973        let logged_defects = get_fake_defects(&mut exec, client);
974        let expected_defects = vec![Defect::Iface(IfaceFailure::EmptyScanResults { iface_id: 0 })];
975        assert_eq!(logged_defects, expected_defects);
976    }
977
978    #[fuchsia::test]
979    fn empty_active_scan_results() {
980        let mut exec = fasync::TestExecutor::new();
981        let (client, mut sme_stream) = exec.run_singlethreaded(create_iface_manager());
982        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
983        let (telemetry_sender, mut telemetry_receiver) = create_telemetry_sender_and_receiver();
984
985        // Issue request to scan.
986        let sme_scan = active_sme_req(vec!["foo"], vec![]);
987        let scan_fut = perform_scan(
988            sme_scan.clone().into(),
989            client.clone(),
990            saved_networks_manager,
991            telemetry_sender,
992        );
993        let mut scan_fut = pin!(scan_fut);
994
995        // Progress scan handler
996        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Pending);
997
998        // Send back empty scan results via the SME
999        assert_matches!(
1000            exec.run_until_stalled(&mut sme_stream.next()),
1001            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan {
1002                req, responder,
1003            }))) => {
1004                assert_eq!(req, sme_scan.clone());
1005                let vmo = write_vmo(vec![]).expect("failed to write VMO");
1006                responder.send(Ok(vmo)).expect("failed to send scan data");
1007            }
1008        );
1009
1010        // Process response from SME (which is empty) and expect the future to complete.
1011        assert_matches!(exec.run_until_stalled(&mut scan_fut),  Poll::Ready((request, results)) => {
1012            assert_eq!(request.sme_req, sme_scan);
1013            assert!(results.unwrap().is_empty());
1014        });
1015
1016        // Verify that a scan defect has not been logged; this should only be logged for
1017        // passive scans because it is common for active scans.
1018        assert_matches!(telemetry_receiver.try_next(), Ok(Some(TelemetryEvent::ScanEvent { scan_defects, .. })) => {
1019            assert!(scan_defects.is_empty());
1020        });
1021
1022        // Verify that no defect was logged.
1023        let logged_defects = get_fake_defects(&mut exec, client);
1024        let expected_defects = vec![];
1025        assert_eq!(logged_defects, expected_defects);
1026    }
1027
1028    /// Verify that saved networks have their hidden network probabilities updated.
1029    #[test_case(active_sme_req(vec![], vec![])          ; "active_sme_req, no ssid")]
1030    #[test_case(active_sme_req(vec![""], vec![])        ; "active_sme_req, wildcard ssid")]
1031    #[test_case(active_sme_req(vec!["", "foo"], vec![]) ; "active_sme_req, wildcard and foo ssid")]
1032    #[test_case(active_sme_req(vec!["foo"], vec![])     ; "active_sme_req, foo ssid")]
1033    #[test_case(passive_sme_req())]
1034    #[fuchsia::test(add_test_attr = false)]
1035    fn scan_updates_hidden_network_probabilities(sme_scan_request: fidl_sme::ScanRequest) {
1036        let mut exec = fasync::TestExecutor::new();
1037        let (client, mut sme_stream) = exec.run_singlethreaded(create_iface_manager());
1038        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
1039        let (telemetry_sender, _telemetry_receiver) = create_telemetry_sender_and_receiver();
1040
1041        // Create the scan info
1042        let MockScanData { sme_results: input_aps, internal_results: scan_results } =
1043            create_scan_ap_data(types::ScanObservation::Unknown);
1044
1045        // Issue request to scan.
1046        let scan_fut = perform_scan(
1047            sme_scan_request.clone().into(),
1048            client,
1049            saved_networks_manager.clone(),
1050            telemetry_sender,
1051        );
1052        let mut scan_fut = pin!(scan_fut);
1053
1054        // Progress scan handler
1055        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Pending);
1056
1057        // Create mock scan data and send it via the SME
1058        assert_matches!(
1059            exec.run_until_stalled(&mut sme_stream.next()),
1060            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan {
1061                req, responder,
1062            }))) => {
1063                assert_eq!(req, sme_scan_request);
1064                let vmo = write_vmo(input_aps).expect("failed to write VMO");
1065                responder.send(Ok(vmo)).expect("failed to send scan data");
1066            }
1067        );
1068
1069        // Process response from SME. If an active scan is requested for the unseen network this
1070        // will be pending, otherwise it will be ready.
1071        let _ = exec.run_until_stalled(&mut scan_fut);
1072
1073        // Verify that the scan results were recorded.
1074        let target_ssids = match sme_scan_request {
1075            fidl_sme::ScanRequest::Passive(_) => vec![],
1076            fidl_sme::ScanRequest::Active(ref req) => {
1077                req.ssids.iter().map(|s| types::Ssid::from_bytes_unchecked(s.to_vec())).collect()
1078            }
1079        };
1080        let mut scan_results_ids: Vec<types::NetworkIdentifierDetailed> = scan_results
1081            .iter()
1082            .map(|scan_result| types::NetworkIdentifierDetailed {
1083                ssid: scan_result.ssid.clone(),
1084                security_type: scan_result.security_type_detailed,
1085            })
1086            .collect();
1087
1088        let scan_result_record_guard =
1089            exec.run_singlethreaded(saved_networks_manager.scan_result_records.lock());
1090        assert_eq!(scan_result_record_guard.len(), 1);
1091        assert_eq!(scan_result_record_guard[0].0, target_ssids);
1092
1093        // Get recorded scan result network ids
1094        let mut recorded_ids = scan_result_record_guard[0]
1095            .1
1096            .keys()
1097            .cloned()
1098            .collect::<Vec<types::NetworkIdentifierDetailed>>();
1099
1100        recorded_ids.sort();
1101        scan_results_ids.sort();
1102        assert_eq!(scan_results_ids, recorded_ids);
1103
1104        // Note: the decision to active scan is non-deterministic (using the hidden network probabilities),
1105        // no need to continue and verify the results in this test case.
1106    }
1107
1108    #[fuchsia::test]
1109    fn bss_to_network_map_duplicated_bss() {
1110        // Create some input data with duplicated BSSID and Network Identifiers
1111        let first_result = fidl_sme::ScanResult {
1112            compatibility: fidl_sme::Compatibility::Compatible(fidl_sme::Compatible {
1113                mutual_security_protocols: vec![fidl_security::Protocol::Wpa3Personal],
1114            }),
1115            timestamp_nanos: zx::MonotonicInstant::get().into_nanos(),
1116            bss_description: random_fidl_bss_description!(
1117                Wpa3,
1118                bssid: [0, 0, 0, 0, 0, 0],
1119                ssid: types::Ssid::try_from("duplicated ssid").unwrap(),
1120                rssi_dbm: 0,
1121                snr_db: 1,
1122                channel: types::WlanChan::new(1, types::Cbw::Cbw20),
1123            ),
1124        };
1125        let second_result = fidl_sme::ScanResult {
1126            compatibility: fidl_sme::Compatibility::Compatible(fidl_sme::Compatible {
1127                mutual_security_protocols: vec![fidl_security::Protocol::Wpa3Personal],
1128            }),
1129            timestamp_nanos: zx::MonotonicInstant::get().into_nanos(),
1130            bss_description: random_fidl_bss_description!(
1131                Wpa3,
1132                ssid: types::Ssid::try_from("duplicated ssid").unwrap(),
1133                bssid: [1, 2, 3, 4, 5, 6],
1134                rssi_dbm: 101,
1135                snr_db: 101,
1136                channel: types::WlanChan::new(101, types::Cbw::Cbw40),
1137            ),
1138        };
1139
1140        let sme_results = [
1141            first_result.clone(),
1142            second_result.clone(),
1143            // same bssid as first_result
1144            fidl_sme::ScanResult {
1145                compatibility: fidl_sme::Compatibility::Compatible(fidl_sme::Compatible {
1146                    mutual_security_protocols: vec![fidl_security::Protocol::Wpa3Personal],
1147                }),
1148                timestamp_nanos: zx::MonotonicInstant::get().into_nanos(),
1149                bss_description: random_fidl_bss_description!(
1150                    Wpa3,
1151                    bssid: [0, 0, 0, 0, 0, 0],
1152                    ssid: types::Ssid::try_from("duplicated ssid").unwrap(),
1153                        rssi_dbm: 13,
1154                        snr_db: 3,
1155                        channel: types::WlanChan::new(14, types::Cbw::Cbw20),
1156                ),
1157            },
1158        ];
1159
1160        let expected_id = types::NetworkIdentifierDetailed {
1161            ssid: types::Ssid::try_from("duplicated ssid").unwrap(),
1162            security_type: types::SecurityTypeDetailed::Wpa3Personal,
1163        };
1164
1165        // We should only see one entry for the duplicated BSSs in the scan results, and a second
1166        // entry for the unique bss
1167        let expected_bss = vec![
1168            types::Bss {
1169                bssid: types::Bssid::from([0, 0, 0, 0, 0, 0]),
1170                signal: types::Signal { rssi_dbm: 0, snr_db: 1 },
1171                timestamp: zx::MonotonicInstant::from_nanos(first_result.timestamp_nanos),
1172                channel: types::WlanChan::new(1, types::Cbw::Cbw20),
1173                observation: types::ScanObservation::Passive,
1174                compatibility: Compatible::expect_ok([SecurityDescriptor::WPA3_PERSONAL]),
1175                bss_description: first_result.bss_description.clone().into(),
1176            },
1177            types::Bss {
1178                bssid: types::Bssid::from([1, 2, 3, 4, 5, 6]),
1179                signal: types::Signal { rssi_dbm: 101, snr_db: 101 },
1180                timestamp: zx::MonotonicInstant::from_nanos(second_result.timestamp_nanos),
1181                channel: types::WlanChan::new(101, types::Cbw::Cbw40),
1182                observation: types::ScanObservation::Passive,
1183                compatibility: Compatible::expect_ok([SecurityDescriptor::WPA3_PERSONAL]),
1184                bss_description: second_result.bss_description.clone().into(),
1185            },
1186        ];
1187
1188        let bss_by_network = bss_to_network_map(
1189            sme_results
1190                .iter()
1191                .map(|scan_result| {
1192                    scan_result.clone().try_into().expect("Failed to convert ScanResult")
1193                })
1194                .collect::<Vec<wlan_common::scan::ScanResult>>(),
1195            &[],
1196            &mut ScanEventInspectData::new(),
1197        );
1198        assert_eq!(bss_by_network.len(), 1);
1199        assert_eq!(bss_by_network[&expected_id], expected_bss);
1200    }
1201
1202    #[test_case(
1203        fidl_sme::ScanErrorCode::InternalError,
1204        types::ScanError::GeneralError,
1205        Defect::Iface(IfaceFailure::FailedScan {iface_id: 0})
1206    )]
1207    #[test_case(
1208        fidl_sme::ScanErrorCode::InternalMlmeError,
1209        types::ScanError::GeneralError,
1210        Defect::Iface(IfaceFailure::FailedScan {iface_id: 0})
1211    )]
1212    #[test_case(
1213        fidl_sme::ScanErrorCode::NotSupported,
1214        types::ScanError::GeneralError,
1215        Defect::Iface(IfaceFailure::FailedScan {iface_id: 0})
1216    )]
1217    #[fuchsia::test(add_test_attr = false)]
1218    fn scan_error_no_retries(
1219        sme_failure_mode: fidl_sme::ScanErrorCode,
1220        policy_failure_mode: types::ScanError,
1221        expected_defect: Defect,
1222    ) {
1223        let mut exec = fasync::TestExecutor::new();
1224        let (client, mut sme_stream) = exec.run_singlethreaded(create_iface_manager());
1225        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
1226        let (telemetry_sender, _telemetry_receiver) = create_telemetry_sender_and_receiver();
1227
1228        // Issue request to scan.
1229        let sme_scan = active_sme_req(vec![], vec![1]);
1230        let scan_fut = perform_scan(
1231            sme_scan.clone().into(),
1232            client.clone(),
1233            saved_networks_manager,
1234            telemetry_sender,
1235        );
1236        let mut scan_fut = pin!(scan_fut);
1237        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Pending);
1238
1239        // Send back a failure to the scan request that was generated.
1240        assert_matches!(
1241            exec.run_until_stalled(&mut sme_stream.next()),
1242            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req: _, responder }))) => {
1243                // Send failed scan response.
1244                responder.send(Err(sme_failure_mode)).expect("failed to send scan error");
1245            }
1246        );
1247
1248        // The scan future should complete with an error.
1249        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Ready((request, results)) => {
1250            assert_eq!(request.sme_req, sme_scan);
1251            assert_eq!(results, Err(policy_failure_mode));
1252        });
1253
1254        // A defect should have been logged on the IfaceManager.
1255        let logged_defects = get_fake_defects(&mut exec, client);
1256        let expected_defects = vec![expected_defect];
1257        assert_eq!(logged_defects, expected_defects);
1258    }
1259
1260    #[fuchsia::test]
1261    fn scan_returns_error_on_timeout() {
1262        let mut exec = fasync::TestExecutor::new_with_fake_time();
1263        let (client, _sme_stream) = run_until_completion(&mut exec, create_iface_manager());
1264        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
1265        let (telemetry_sender, _telemetry_receiver) = create_telemetry_sender_and_receiver();
1266
1267        // Issue request to scan.
1268        let sme_scan = passive_sme_req();
1269        let scan_fut =
1270            perform_scan(sme_scan.clone().into(), client, saved_networks_manager, telemetry_sender);
1271        let mut scan_fut = pin!(scan_fut);
1272
1273        // Progress scan handler forward so that it will respond to the iterator get next request.
1274        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Pending);
1275
1276        // Wake up the next timer, which should be the timeour on the scan request.
1277        assert!(exec.wake_next_timer().is_some());
1278
1279        // Check that an error is returned for the scan and there are no location sensor results.
1280        assert_matches!(exec.run_until_stalled(&mut scan_fut), Poll::Ready((request, results)) => {
1281            assert_eq!(request.sme_req, sme_scan);
1282            assert_eq!(results, Err(types::ScanError::GeneralError));
1283        });
1284    }
1285
1286    #[test_case(fidl_sme::ScanErrorCode::NotSupported, ScanIssue::ScanFailure)]
1287    #[test_case(fidl_sme::ScanErrorCode::InternalError, ScanIssue::ScanFailure)]
1288    #[test_case(fidl_sme::ScanErrorCode::InternalMlmeError, ScanIssue::ScanFailure)]
1289    #[test_case(fidl_sme::ScanErrorCode::ShouldWait, ScanIssue::AbortedScan)]
1290    #[test_case(fidl_sme::ScanErrorCode::CanceledByDriverOrFirmware, ScanIssue::AbortedScan)]
1291    #[fuchsia::test(add_test_attr = false)]
1292    fn test_scan_error_metric_conversion(
1293        scan_error: fidl_sme::ScanErrorCode,
1294        expected_issue: ScanIssue,
1295    ) {
1296        let mut scan_defects = vec![];
1297        log_metric_for_scan_error(&scan_error, &mut scan_defects);
1298        assert_eq!(scan_defects, vec![expected_issue]);
1299    }
1300
1301    #[test_case(Err(types::ScanError::GeneralError), Some(Defect::Iface(IfaceFailure::FailedScan { iface_id: 0 })))]
1302    #[test_case(Err(types::ScanError::Cancelled), Some(Defect::Iface(IfaceFailure::CanceledScan { iface_id: 0 })))]
1303    #[test_case(Ok(vec![]), Some(Defect::Iface(IfaceFailure::EmptyScanResults { iface_id: 0 })))]
1304    #[test_case(Ok(vec![wlan_common::scan::ScanResult::try_from(
1305            fidl_sme::ScanResult {
1306                bss_description: random_fidl_bss_description!(Wpa2, ssid: types::Ssid::try_from("other ssid").unwrap()),
1307                ..generate_random_sme_scan_result()
1308            },
1309        ).expect("failed scan result conversion")]),
1310        None
1311    )]
1312    #[fuchsia::test(add_test_attr = false)]
1313    fn test_scan_defect_reporting(
1314        scan_result: Result<Vec<wlan_common::scan::ScanResult>, types::ScanError>,
1315        expected_defect: Option<Defect>,
1316    ) {
1317        let mut exec = fasync::TestExecutor::new();
1318        let (iface_manager, _) = exec.run_singlethreaded(create_iface_manager());
1319        let scan_request = passive_sme_req();
1320
1321        // Get the SME out of the IfaceManager.
1322        let sme = {
1323            let cloned_iface_manager = iface_manager.clone();
1324            let fut = async move {
1325                let mut iface_manager = cloned_iface_manager.lock().await;
1326                iface_manager.get_sme_proxy_for_scan().await
1327            };
1328            let mut fut = pin!(fut);
1329            assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(Ok(sme)) => sme)
1330        };
1331
1332        // Report the desired scan error or success.
1333        let fut = report_scan_defects_to_sme(&sme, &scan_result, &scan_request);
1334        let mut fut = pin!(fut);
1335        assert_matches!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
1336
1337        // Based on the expected defect (or lack thereof), ensure that the correct value is obsered
1338        // on the receiver.
1339        // Verify that a defect was logged.
1340        let logged_defects = get_fake_defects(&mut exec, iface_manager);
1341        match expected_defect {
1342            Some(defect) => {
1343                assert_eq!(logged_defects, vec![defect])
1344            }
1345            None => assert!(logged_defects.is_empty()),
1346        }
1347    }
1348
1349    #[fuchsia::test]
1350    fn scanning_loop_handles_sequential_requests() {
1351        let mut exec = fasync::TestExecutor::new();
1352        let (iface_mgr, mut sme_stream) = exec.run_singlethreaded(create_iface_manager());
1353        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
1354        let (telemetry_sender, _telemetry_receiver) = create_telemetry_sender_and_receiver();
1355        let (location_sensor, _, _) = MockScanResultConsumer::new();
1356        let (scan_request_sender, scan_request_receiver) = mpsc::channel(100);
1357        let scan_requester = Arc::new(ScanRequester { sender: scan_request_sender });
1358        let scanning_loop = serve_scanning_loop(
1359            iface_mgr.clone(),
1360            saved_networks_manager.clone(),
1361            telemetry_sender,
1362            location_sensor,
1363            scan_request_receiver,
1364        );
1365        let mut scanning_loop = pin!(scanning_loop);
1366
1367        // Issue request to scan.
1368        let first_req_channels = vec![13];
1369        let scan_req_fut1 = scan_requester.perform_scan(
1370            ScanReason::BssSelection,
1371            vec!["foo".try_into().unwrap()],
1372            first_req_channels.iter().map(|c| generate_channel(*c)).collect(),
1373        );
1374        let mut scan_req_fut1 = pin!(scan_req_fut1);
1375        assert_matches!(exec.run_until_stalled(&mut scan_req_fut1), Poll::Pending);
1376        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1377
1378        // Send back a failure to the scan request that was generated.
1379        assert_matches!(
1380            exec.run_until_stalled(&mut sme_stream.next()),
1381            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req, responder }))) => {
1382                // Make sure it's the right scan
1383                assert_matches!(req, fidl_sme::ScanRequest::Active(req) => {
1384                    assert_eq!(req.channels, first_req_channels)
1385                });
1386                // Send failed scan response.
1387                responder.send(Err(fidl_sme::ScanErrorCode::InternalError)).expect("failed to send scan error");
1388            }
1389        );
1390        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1391
1392        // The scan request future should complete with an error.
1393        assert_matches!(exec.run_until_stalled(&mut scan_req_fut1), Poll::Ready(results) => {
1394            assert_eq!(results, Err(types::ScanError::GeneralError));
1395        });
1396
1397        // There should be no other SME requests in the queue
1398        assert_matches!(exec.run_until_stalled(&mut sme_stream.next()), Poll::Pending);
1399
1400        // Issue another request to scan.
1401        let second_req_channels = vec![55];
1402        let scan_req_fut2 = scan_requester.perform_scan(
1403            ScanReason::BssSelection,
1404            vec!["foo".try_into().unwrap()],
1405            second_req_channels.iter().map(|c| generate_channel(*c)).collect(),
1406        );
1407        let mut scan_req_fut2 = pin!(scan_req_fut2);
1408        assert_matches!(exec.run_until_stalled(&mut scan_req_fut2), Poll::Pending);
1409        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1410
1411        // Send back a failure to the scan request that was generated.
1412        assert_matches!(
1413            exec.run_until_stalled(&mut sme_stream.next()),
1414            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req, responder }))) => {
1415                // Make sure it's the right scan
1416                assert_matches!(req, fidl_sme::ScanRequest::Active(req) => {
1417                    assert_eq!(req.channels, second_req_channels)
1418                });
1419                // Send failed scan response.
1420                responder.send(Err(fidl_sme::ScanErrorCode::InternalError)).expect("failed to send scan error");
1421            }
1422        );
1423        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1424
1425        // The scan request future should complete with an error.
1426        assert_matches!(exec.run_until_stalled(&mut scan_req_fut2), Poll::Ready(results) => {
1427            assert_eq!(results, Err(types::ScanError::GeneralError));
1428        });
1429
1430        // There should be no other SME requests in the queue
1431        assert_matches!(exec.run_until_stalled(&mut sme_stream.next()), Poll::Pending);
1432    }
1433
1434    #[fuchsia::test]
1435    fn scanning_loop_handles_overlapping_requests() {
1436        let mut exec = fasync::TestExecutor::new();
1437        let (iface_mgr, mut sme_stream) = exec.run_singlethreaded(create_iface_manager());
1438        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
1439        let (telemetry_sender, _telemetry_receiver) = create_telemetry_sender_and_receiver();
1440        let (location_sensor, _, _) = MockScanResultConsumer::new();
1441        let (scan_request_sender, scan_request_receiver) = mpsc::channel(100);
1442        let scan_requester = Arc::new(ScanRequester { sender: scan_request_sender });
1443        let scanning_loop = serve_scanning_loop(
1444            iface_mgr.clone(),
1445            saved_networks_manager.clone(),
1446            telemetry_sender,
1447            location_sensor,
1448            scan_request_receiver,
1449        );
1450        let mut scanning_loop = pin!(scanning_loop);
1451
1452        // Issue request to scan.
1453        let first_req_channels = vec![13];
1454        let scan_req_fut1 = scan_requester.perform_scan(
1455            ScanReason::BssSelection,
1456            vec!["foo".try_into().unwrap()],
1457            first_req_channels.iter().map(|c| generate_channel(*c)).collect(),
1458        );
1459        let mut scan_req_fut1 = pin!(scan_req_fut1);
1460        assert_matches!(exec.run_until_stalled(&mut scan_req_fut1), Poll::Pending);
1461        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1462
1463        // Check the scan request was sent to the SME.
1464        let responder1 = assert_matches!(
1465            exec.run_until_stalled(&mut sme_stream.next()),
1466            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req, responder }))) => {
1467                // Make sure it's the right scan
1468                assert_matches!(req, fidl_sme::ScanRequest::Active(req) => {
1469                    assert_eq!(req.channels, first_req_channels)
1470                });
1471                responder
1472            }
1473        );
1474        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1475
1476        // Issue another request to scan.
1477        let second_req_channels = vec![55];
1478        let scan_req_fut2 = scan_requester.perform_scan(
1479            ScanReason::BssSelection,
1480            vec!["foo".try_into().unwrap()],
1481            second_req_channels.iter().map(|c| generate_channel(*c)).collect(),
1482        );
1483        let mut scan_req_fut2 = pin!(scan_req_fut2);
1484        assert_matches!(exec.run_until_stalled(&mut scan_req_fut2), Poll::Pending);
1485        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1486
1487        // Both requests are pending
1488        assert_matches!(exec.run_until_stalled(&mut scan_req_fut1), Poll::Pending);
1489        assert_matches!(exec.run_until_stalled(&mut scan_req_fut2), Poll::Pending);
1490        // There should be no other SME requests in the queue
1491        assert_matches!(exec.run_until_stalled(&mut sme_stream.next()), Poll::Pending);
1492
1493        // Send back a failed scan response.
1494        responder1
1495            .send(Err(fidl_sme::ScanErrorCode::InternalError))
1496            .expect("failed to send scan error");
1497        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1498
1499        // There should immediately be a new SME scan for the second request
1500        assert_matches!(
1501            exec.run_until_stalled(&mut sme_stream.next()),
1502            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req, responder }))) => {
1503                // Make sure it's the right scan
1504                assert_matches!(req, fidl_sme::ScanRequest::Active(req) => {
1505                    assert_eq!(req.channels, second_req_channels)
1506                });
1507                // Send failed scan response.
1508                responder.send(Err(fidl_sme::ScanErrorCode::InternalError)).expect("failed to send scan error");
1509            }
1510        );
1511        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1512
1513        // Both scan request futures should complete with an error.
1514        assert_matches!(exec.run_until_stalled(&mut scan_req_fut1), Poll::Ready(results) => {
1515            assert_eq!(results, Err(types::ScanError::GeneralError));
1516        });
1517        assert_matches!(exec.run_until_stalled(&mut scan_req_fut2), Poll::Ready(results) => {
1518            assert_eq!(results, Err(types::ScanError::GeneralError));
1519        });
1520
1521        // There should be no other SME requests in the queue
1522        assert_matches!(exec.run_until_stalled(&mut sme_stream.next()), Poll::Pending);
1523    }
1524
1525    #[fuchsia::test]
1526    fn scanning_loop_sends_results_to_requester_and_location_sensor() {
1527        let mut exec = fasync::TestExecutor::new();
1528        let (iface_mgr, mut sme_stream) = exec.run_singlethreaded(create_iface_manager());
1529        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
1530        let (telemetry_sender, _telemetry_receiver) = create_telemetry_sender_and_receiver();
1531        let (location_sensor, location_sensor_results, _) = MockScanResultConsumer::new();
1532        let (scan_request_sender, scan_request_receiver) = mpsc::channel(100);
1533        let scan_requester = Arc::new(ScanRequester { sender: scan_request_sender });
1534        let scanning_loop = serve_scanning_loop(
1535            iface_mgr.clone(),
1536            saved_networks_manager.clone(),
1537            telemetry_sender,
1538            location_sensor,
1539            scan_request_receiver,
1540        );
1541        let mut scanning_loop = pin!(scanning_loop);
1542
1543        // Issue request to scan.
1544        let scan_req_fut = scan_requester.perform_scan(ScanReason::BssSelection, vec![], vec![]);
1545        let mut scan_req_fut = pin!(scan_req_fut);
1546        assert_matches!(exec.run_until_stalled(&mut scan_req_fut), Poll::Pending);
1547        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1548
1549        // Send back scan results
1550        assert_matches!(
1551            exec.run_until_stalled(&mut sme_stream.next()),
1552            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req: _, responder }))) => {
1553                let results = vec![generate_random_sme_scan_result(), generate_random_sme_scan_result()];
1554                let vmo = write_vmo(results).expect("failed to write VMO");
1555                responder.send(Ok(vmo)).expect("failed to send scan error");
1556            }
1557        );
1558        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1559
1560        // The scan request future should complete.
1561        assert_matches!(exec.run_until_stalled(&mut scan_req_fut), Poll::Ready(Ok(results)) => {
1562            assert_eq!(results.len(), 2);
1563        });
1564
1565        // Check location sensor got results
1566        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1567        assert_matches!(
1568            &*exec.run_singlethreaded(location_sensor_results.lock()),
1569            Some(results) => {
1570                assert_eq!(results.len(), 2);
1571            }
1572        );
1573    }
1574
1575    #[fuchsia::test]
1576    fn scanning_loop_location_sensor_timeout_works() {
1577        let mut exec = fasync::TestExecutor::new();
1578        let (iface_mgr, mut sme_stream) = exec.run_singlethreaded(create_iface_manager());
1579        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
1580        let (telemetry_sender, _telemetry_receiver) = create_telemetry_sender_and_receiver();
1581        let (location_sensor, location_sensor_results, location_sensor_stalled) =
1582            MockScanResultConsumer::new();
1583        let (scan_request_sender, scan_request_receiver) = mpsc::channel(100);
1584        let scan_requester = Arc::new(ScanRequester { sender: scan_request_sender });
1585        let scanning_loop = serve_scanning_loop(
1586            iface_mgr.clone(),
1587            saved_networks_manager.clone(),
1588            telemetry_sender,
1589            location_sensor,
1590            scan_request_receiver,
1591        );
1592        let mut scanning_loop = pin!(scanning_loop);
1593
1594        // Make location sensor stalled
1595        *(exec.run_singlethreaded(location_sensor_stalled.lock())) = true;
1596
1597        // Issue request to scan.
1598        let scan_req_fut = scan_requester.perform_scan(ScanReason::BssSelection, vec![], vec![]);
1599        let mut scan_req_fut = pin!(scan_req_fut);
1600        assert_matches!(exec.run_until_stalled(&mut scan_req_fut), Poll::Pending);
1601        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1602
1603        // Send back scan results
1604        assert_matches!(
1605            exec.run_until_stalled(&mut sme_stream.next()),
1606            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req: _, responder }))) => {
1607                let results = vec![generate_random_sme_scan_result(), generate_random_sme_scan_result()];
1608                let vmo = write_vmo(results).expect("failed to write VMO");
1609                responder.send(Ok(vmo)).expect("failed to send scan error");
1610            }
1611        );
1612        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1613
1614        // Check location sensor didn't get any results
1615        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1616        assert_matches!(&*exec.run_singlethreaded(location_sensor_results.lock()), None);
1617
1618        // Make location sensor *not* stalled
1619        *(exec.run_singlethreaded(location_sensor_stalled.lock())) = false;
1620
1621        // Issue another request to scan.
1622        let scan_req_fut = scan_requester.perform_scan(ScanReason::BssSelection, vec![], vec![]);
1623        let mut scan_req_fut = pin!(scan_req_fut);
1624        assert_matches!(exec.run_until_stalled(&mut scan_req_fut), Poll::Pending);
1625        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1626
1627        // Send back scan results
1628        assert_matches!(
1629            exec.run_until_stalled(&mut sme_stream.next()),
1630            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req: _, responder }))) => {
1631                let results = vec![generate_random_sme_scan_result(), generate_random_sme_scan_result()];
1632                let vmo = write_vmo(results).expect("failed to write VMO");
1633                responder.send(Ok(vmo)).expect("failed to send scan error");
1634            }
1635        );
1636        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1637
1638        // Check location sensor got results
1639        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1640        assert_matches!(
1641            &*exec.run_singlethreaded(location_sensor_results.lock()),
1642            Some(results) => {
1643                assert_eq!(results.len(), 2);
1644            }
1645        );
1646    }
1647
1648    #[fuchsia::test]
1649    fn scanning_loops_sends_inspect_data_to_telemetry() {
1650        let mut exec = fasync::TestExecutor::new();
1651        let (iface_mgr, mut sme_stream) = exec.run_singlethreaded(create_iface_manager());
1652        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
1653        let (telemetry_sender, mut telemetry_receiver) = create_telemetry_sender_and_receiver();
1654        let (location_sensor, _, _) = MockScanResultConsumer::new();
1655        let (scan_request_sender, scan_request_receiver) = mpsc::channel(100);
1656        let scan_requester = Arc::new(ScanRequester { sender: scan_request_sender });
1657        let scanning_loop = serve_scanning_loop(
1658            iface_mgr.clone(),
1659            saved_networks_manager.clone(),
1660            telemetry_sender,
1661            location_sensor,
1662            scan_request_receiver,
1663        );
1664        let mut scanning_loop = pin!(scanning_loop);
1665
1666        // Issue request to scan
1667        let scan_req_fut = scan_requester.perform_scan(ScanReason::BssSelection, vec![], vec![]);
1668        let mut scan_req_fut = pin!(scan_req_fut);
1669        assert_matches!(exec.run_until_stalled(&mut scan_req_fut), Poll::Pending);
1670        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1671
1672        // Prepare scan results with unknown protection IEs
1673        let bss_description = fake_bss_description!(Wpa2, ies_overrides: IesOverrides::new().set(IeType::RSNE, fake_unknown_rsne()[2..].to_vec()));
1674        let scan_result = fidl_sme::ScanResult {
1675            bss_description: bss_description.into(),
1676            ..generate_random_sme_scan_result()
1677        };
1678
1679        // Send back scan results
1680        assert_matches!(
1681            exec.run_until_stalled(&mut sme_stream.next()),
1682            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan {
1683                req, responder,
1684            }))) => {
1685                assert_eq!(req, passive_sme_req());
1686                let vmo = write_vmo(vec![scan_result.clone()]).expect("failed to write VMO");
1687                responder.send(Ok(vmo)).expect("failed to send scan data");
1688            }
1689        );
1690
1691        // Process scan handler
1692        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1693
1694        // The scan request future should complete.
1695        assert_matches!(exec.run_until_stalled(&mut scan_req_fut), Poll::Ready(Ok(results)) => {
1696            assert_eq!(results.len(), 1);
1697        });
1698
1699        // Verify inspect data was sent to telemetry module.
1700        let readable_ie: String =
1701            scan_result.bss_description.ies.iter().map(|n| n.to_string()).join(",");
1702        assert_matches!(
1703            telemetry_receiver.try_next(),
1704            Ok(Some(TelemetryEvent::ScanEvent {inspect_data, scan_defects})) => {
1705                assert_eq!(scan_defects, vec![]);
1706                assert_eq!(inspect_data.unknown_protection_ies, vec![readable_ie]);
1707        });
1708    }
1709
1710    #[test_case(fidl_sme::ScanErrorCode::ShouldWait, false; "Scan error ShouldWait with failed retry")]
1711    #[test_case(fidl_sme::ScanErrorCode::ShouldWait, true; "Scan error ShouldWait with successful retry")]
1712    #[test_case(fidl_sme::ScanErrorCode::CanceledByDriverOrFirmware, true; "Scan error CanceledByDriverOrFirmware with successful retry")]
1713    #[fuchsia::test]
1714    fn scanning_loop_retries_cancelled_request_once(
1715        error_code: fidl_sme::ScanErrorCode,
1716        retry_succeeds: bool,
1717    ) {
1718        let mut exec = fasync::TestExecutor::new_with_fake_time();
1719        let (iface_mgr, mut sme_stream) = run_until_completion(&mut exec, create_iface_manager());
1720        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
1721        let (telemetry_sender, _telemetry_receiver) = create_telemetry_sender_and_receiver();
1722        let (location_sensor, _, _) = MockScanResultConsumer::new();
1723        let (scan_request_sender, scan_request_receiver) = mpsc::channel(100);
1724        let scan_requester = Arc::new(ScanRequester { sender: scan_request_sender });
1725        let scanning_loop = serve_scanning_loop(
1726            iface_mgr.clone(),
1727            saved_networks_manager.clone(),
1728            telemetry_sender,
1729            location_sensor,
1730            scan_request_receiver,
1731        );
1732        let mut scanning_loop = pin!(scanning_loop);
1733
1734        // Issue request to scan.
1735        let req_channels = vec![13];
1736        let scan_req_fut = scan_requester.perform_scan(
1737            ScanReason::BssSelection,
1738            vec!["foo".try_into().unwrap()],
1739            req_channels.iter().map(|c| generate_channel(*c)).collect(),
1740        );
1741        let mut scan_req_fut = pin!(scan_req_fut);
1742        assert_matches!(exec.run_until_stalled(&mut scan_req_fut), Poll::Pending);
1743        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1744
1745        // Check that the scan request was sent to the SME.
1746        let responder = assert_matches!(
1747            exec.run_until_stalled(&mut sme_stream.next()),
1748            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req, responder }))) => {
1749                // Make sure it's the right scan
1750                assert_matches!(req, fidl_sme::ScanRequest::Active(req) => {
1751                    assert_eq!(req.channels, req_channels)
1752                });
1753                responder
1754            }
1755        );
1756        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1757
1758        // Send back a error from SME for the request.
1759        responder.send(Err(error_code)).expect("failed to send scan error");
1760        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1761
1762        // Request should return still be pending, awaiting retry.
1763        assert_matches!(exec.run_until_stalled(&mut scan_req_fut), Poll::Pending);
1764
1765        // There should be no new SME requests yet.
1766        assert_matches!(exec.run_until_stalled(&mut sme_stream.next()), Poll::Pending);
1767
1768        // Wake up the back off timer and advance the scan request future.
1769        assert!(exec.wake_next_timer().is_some());
1770        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1771
1772        // Verify the retry scan request was sent to SME.
1773        let responder = assert_matches!(
1774            exec.run_until_stalled(&mut sme_stream.next()),
1775            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req, responder }))) => {
1776                assert_matches!(req, fidl_sme::ScanRequest::Active(req) => {
1777                    assert_eq!(req.channels, req_channels)
1778                });
1779                responder
1780            }
1781        );
1782
1783        if retry_succeeds {
1784            // Create mock scan data and send it via the SME. Although it's an active scan, the
1785            // scan doesn't target any of these SSIDs, so results should be ScanObservation::Passive
1786            let MockScanData { sme_results: input_aps, internal_results: _internal_aps } =
1787                create_scan_ap_data(types::ScanObservation::Passive);
1788            let vmo = write_vmo(input_aps).expect("failed to write VMO");
1789            responder.send(Ok(vmo)).expect("failed to send scan data");
1790            assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1791
1792            // Verify one defect was logged.
1793            let logged_defects = get_fake_defects(&mut exec, iface_mgr);
1794            let expected_defects = vec![Defect::Iface(IfaceFailure::CanceledScan { iface_id: 0 })];
1795            assert_eq!(logged_defects, expected_defects);
1796        } else {
1797            // Send back a error from SME.
1798            responder.send(Err(error_code)).expect("failed to send scan error");
1799            assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1800
1801            // Verify that both defects were logged.
1802            let logged_defects = get_fake_defects(&mut exec, iface_mgr);
1803            let expected_defects = vec![
1804                Defect::Iface(IfaceFailure::CanceledScan { iface_id: 0 }),
1805                Defect::Iface(IfaceFailure::CanceledScan { iface_id: 0 }),
1806            ];
1807            assert_eq!(logged_defects, expected_defects);
1808        }
1809        // Request should get a response now.
1810        assert_matches!(exec.run_until_stalled(&mut scan_req_fut), Poll::Ready(_));
1811
1812        // There should be no new SME requests.
1813        assert_matches!(exec.run_until_stalled(&mut sme_stream.next()), Poll::Pending);
1814    }
1815
1816    #[fuchsia::test]
1817    fn scanning_loop_backs_off_after_cancelled_request() {
1818        let mut exec = fasync::TestExecutor::new_with_fake_time();
1819        let (iface_mgr, mut sme_stream) = run_until_completion(&mut exec, create_iface_manager());
1820        let saved_networks_manager = Arc::new(FakeSavedNetworksManager::new());
1821        let (telemetry_sender, _telemetry_receiver) = create_telemetry_sender_and_receiver();
1822        let (location_sensor, _, _) = MockScanResultConsumer::new();
1823        let (scan_request_sender, scan_request_receiver) = mpsc::channel(100);
1824        let scan_requester = Arc::new(ScanRequester { sender: scan_request_sender });
1825        let scanning_loop = serve_scanning_loop(
1826            iface_mgr.clone(),
1827            saved_networks_manager.clone(),
1828            telemetry_sender,
1829            location_sensor,
1830            scan_request_receiver,
1831        );
1832        let mut scanning_loop = pin!(scanning_loop);
1833
1834        // Issue first request to scan.
1835        let first_req_channels = vec![13];
1836        let scan_req_fut1 = scan_requester.perform_scan(
1837            ScanReason::BssSelection,
1838            vec!["foo".try_into().unwrap()],
1839            first_req_channels.iter().map(|c| generate_channel(*c)).collect(),
1840        );
1841        let mut scan_req_fut1 = pin!(scan_req_fut1);
1842        assert_matches!(exec.run_until_stalled(&mut scan_req_fut1), Poll::Pending);
1843        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1844
1845        // Check the first scan request was sent to the SME.
1846        let responder = assert_matches!(
1847            exec.run_until_stalled(&mut sme_stream.next()),
1848            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req, responder }))) => {
1849                // Make sure it's the right scan
1850                assert_matches!(req, fidl_sme::ScanRequest::Active(req) => {
1851                    assert_eq!(req.channels, first_req_channels)
1852                });
1853                responder
1854            }
1855        );
1856
1857        // Issue a second request to scan.
1858        let second_req_channels = vec![55];
1859        let scan_req_fut2 = scan_requester.perform_scan(
1860            ScanReason::BssSelection,
1861            vec!["foo".try_into().unwrap()],
1862            second_req_channels.iter().map(|c| generate_channel(*c)).collect(),
1863        );
1864        let mut scan_req_fut2 = pin!(scan_req_fut2);
1865        assert_matches!(exec.run_until_stalled(&mut scan_req_fut2), Poll::Pending);
1866        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1867
1868        // There should be no new SME requests in the queue.
1869        assert_matches!(exec.run_until_stalled(&mut sme_stream.next()), Poll::Pending);
1870
1871        // Send back a ShouldWait error from SME for the first request.
1872        responder
1873            .send(Err(fidl_sme::ScanErrorCode::ShouldWait))
1874            .expect("failed to send scan error");
1875        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1876
1877        // First request still be pending, as it awaits a retry.
1878        assert_matches!(exec.run_until_stalled(&mut scan_req_fut1), Poll::Pending);
1879
1880        // There should be no new SME requests, since the first request should be backing off
1881        // before issuing a retry.
1882        assert_matches!(exec.run_until_stalled(&mut sme_stream.next()), Poll::Pending);
1883
1884        // Wake up the back off timer and advance the scan request future.
1885        assert!(exec.wake_next_timer().is_some());
1886        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1887
1888        // Verify the retry scan request was sent to SME.
1889        let responder = assert_matches!(
1890            exec.run_until_stalled(&mut sme_stream.next()),
1891            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req, responder }))) => {
1892                // Make sure it's the right scan
1893                assert_matches!(req, fidl_sme::ScanRequest::Active(req) => {
1894                    assert_eq!(req.channels, first_req_channels)
1895                });
1896                responder
1897            }
1898        );
1899
1900        // Send back another ShouldWait error from SME for the first request retry.
1901        responder
1902            .send(Err(fidl_sme::ScanErrorCode::ShouldWait))
1903            .expect("failed to send scan error");
1904        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1905
1906        // The first scan req future should now be Ready, returning a Cancelled error.
1907        assert_matches!(exec.run_until_stalled(&mut scan_req_fut1), Poll::Ready(results) => {
1908            assert_eq!(results, Err(types::ScanError::Cancelled));
1909        });
1910
1911        // There should be no SME requests in the queue, because the scan loop should be backing
1912        // off before serviving the next scan request.
1913        assert_matches!(exec.run_until_stalled(&mut sme_stream.next()), Poll::Pending);
1914
1915        // Wake up the back off timer.
1916        assert!(exec.wake_next_timer().is_some());
1917        assert_matches!(exec.run_until_stalled(&mut scanning_loop), Poll::Pending);
1918
1919        // There should now be an SME scan request for the second scan req.
1920        assert_matches!(
1921            exec.run_until_stalled(&mut sme_stream.next()),
1922            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req, .. }))) => {
1923                // Make sure it's the right scan
1924                assert_matches!(req, fidl_sme::ScanRequest::Active(req) => {
1925                    assert_eq!(req.channels, second_req_channels)
1926                });
1927            }
1928        );
1929    }
1930}