Skip to main content

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