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