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