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