1mod bound;
6mod channel_switch;
7mod convert_beacon;
8mod lost_bss;
9mod scanner;
10mod state;
11mod station;
12
13use bound::BoundClient;
14use station::{Client, ParsedConnectRequest};
15#[cfg(test)]
16mod test_utils;
17
18use crate::ddk_converter;
19use crate::device::{self, DeviceOps};
20use crate::error::Error;
21use channel_switch::ChannelState;
22use fidl_fuchsia_wlan_common as fidl_common;
23use fidl_fuchsia_wlan_driver as fidl_driver_common;
24use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
25use fidl_fuchsia_wlan_minstrel as fidl_minstrel;
26use fidl_fuchsia_wlan_mlme as fidl_mlme;
27use fidl_fuchsia_wlan_softmac as fidl_softmac;
28use fidl_fuchsia_wlan_stats as fidl_stats;
29use fuchsia_trace as trace;
30use ieee80211::{Bssid, MacAddr, MacAddrBytes};
31use log::{error, warn};
32use scanner::Scanner;
33use wlan_common::bss::BssDescription;
34use wlan_common::capabilities::{ClientCapabilities, derive_join_capabilities};
35use wlan_common::channel::Channel;
36use wlan_common::ie::{self, Id};
37use wlan_common::mac::{self, CapabilityInfo};
38use wlan_common::sequence::SequenceManager;
39use wlan_common::timer::Timer;
40use wlan_trace as wtrace;
41use zerocopy::SplitByteSlice;
42
43pub use scanner::ScanError;
44
45#[derive(Debug, Clone, PartialEq)]
46pub enum TimedEvent {
47 Connecting,
49 Reassociating,
51 AssociationStatusCheck,
54 ChannelSwitch,
56}
57
58#[cfg(test)]
59impl TimedEvent {
60 fn class(&self) -> TimedEventClass {
61 match self {
62 Self::Connecting => TimedEventClass::Connecting,
63 Self::Reassociating => TimedEventClass::Reassociating,
64 Self::AssociationStatusCheck => TimedEventClass::AssociationStatusCheck,
65 Self::ChannelSwitch => TimedEventClass::ChannelSwitch,
66 }
67 }
68}
69
70#[cfg(test)]
71#[derive(Debug, PartialEq, Eq, Hash)]
72pub enum TimedEventClass {
73 Connecting,
74 Reassociating,
75 AssociationStatusCheck,
76 ChannelSwitch,
77}
78
79#[repr(C)]
82#[derive(Debug, Clone, Default)]
83pub struct ClientConfig {
84 pub ensure_on_channel_time: zx::sys::zx_duration_t,
85}
86
87pub struct Context<D> {
88 _config: ClientConfig,
89 device: D,
90 timer: Timer<TimedEvent>,
91 seq_mgr: SequenceManager,
92}
93
94pub struct ClientMlme<D> {
95 sta: Option<Client>,
96 ctx: Context<D>,
97 scanner: Scanner,
98 channel_state: ChannelState,
99}
100impl<D: DeviceOps> crate::MlmeImpl for ClientMlme<D> {
101 type Config = ClientConfig;
102 type Device = D;
103 type TimerEvent = TimedEvent;
104 async fn new(
105 config: Self::Config,
106 mut device: Self::Device,
107 timer: Timer<TimedEvent>,
108 ) -> Result<Self, anyhow::Error> {
109 let iface_mac = device::try_query_iface_mac(&mut device).await?;
110 Ok(Self {
111 sta: None,
112 ctx: Context { _config: config, device, timer, seq_mgr: SequenceManager::new() },
113 scanner: Scanner::new(iface_mac.into()),
114 channel_state: Default::default(),
115 })
116 }
117 async fn handle_mlme_request(
118 &mut self,
119 req: wlan_sme::MlmeRequest,
120 ) -> Result<(), anyhow::Error> {
121 match req {
122 wlan_sme::MlmeRequest::Scan(req) => {
123 self.on_sme_scan(req).await;
124 Ok(())
125 }
126 wlan_sme::MlmeRequest::Connect(req) => {
127 self.on_sme_connect(req).await?;
128 Ok(())
129 }
130 wlan_sme::MlmeRequest::GetIfaceStats(responder) => {
131 self.on_sme_get_iface_stats(responder)?;
132 Ok(())
133 }
134 wlan_sme::MlmeRequest::GetIfaceHistogramStats(responder) => {
135 self.on_sme_get_iface_histogram_stats(responder)?;
136 Ok(())
137 }
138 wlan_sme::MlmeRequest::QueryDeviceInfo(responder) => {
139 self.on_sme_query_device_info(responder).await?;
140 Ok(())
141 }
142 wlan_sme::MlmeRequest::QueryMacSublayerSupport(responder) => {
143 self.on_sme_query_mac_sublayer_support(responder).await?;
144 Ok(())
145 }
146 wlan_sme::MlmeRequest::QuerySecuritySupport(responder) => {
147 self.on_sme_query_security_support(responder).await?;
148 Ok(())
149 }
150 wlan_sme::MlmeRequest::QuerySpectrumManagementSupport(responder) => {
151 self.on_sme_query_spectrum_management_support(responder).await?;
152 Ok(())
153 }
154 wlan_sme::MlmeRequest::ListMinstrelPeers(responder) => {
155 self.on_sme_list_minstrel_peers(responder)?;
156 Ok(())
157 }
158 wlan_sme::MlmeRequest::GetMinstrelStats(req, responder) => {
159 self.on_sme_get_minstrel_stats(responder, &req.peer_addr.into())?;
160 Ok(())
161 }
162 wlan_sme::MlmeRequest::GetSignalReport(responder) => {
163 self.on_sme_get_signal_report(responder);
164 Ok(())
165 }
166 req if self.sta.is_some() => {
167 let sta = self.sta.as_mut().unwrap();
168 sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
169 .handle_mlme_request(req)
170 .await;
171 Ok(())
172 }
173 unhandled_request => {
174 if let wlan_sme::MlmeRequest::Reconnect(req) = &unhandled_request {
175 self.ctx.device.send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf {
176 resp: fidl_mlme::ConnectConfirm {
177 peer_sta_address: req.peer_sta_address,
178 result_code: fidl_ieee80211::StatusCode::DeniedNoAssociationExists,
179 association_id: 0,
180 association_ies: vec![],
181 },
182 })?;
183 }
184
185 Err(Error::Status(
186 format!(
187 "Failed to handle {} MLME request: request is unhandled in the current state. \
188 Connection context exists: {}, Main channel: {:?}, Scanning: {}.",
189 unhandled_request.name(),
190 self.sta.is_some(),
191 self.channel_state.get_primary(),
192 self.scanner.is_scanning(),
193 ),
194 zx::Status::BAD_STATE,
195 ).into())
196 }
197 }
198 }
199 async fn handle_mac_frame_rx(
200 &mut self,
201 bytes: &[u8],
202 rx_info: fidl_softmac::WlanRxInfo,
203 async_id: trace::Id,
204 ) {
205 wtrace::duration!("ClientMlme::handle_mac_frame_rx");
206 if let Some(mgmt_frame) = mac::MgmtFrame::parse(bytes, false) {
208 let bssid = Bssid::from(mgmt_frame.mgmt_hdr.addr3);
209 match mgmt_frame.try_into_mgmt_body().1 {
210 Some(mac::MgmtBody::Beacon { bcn_hdr, elements }) => {
211 wtrace::duration!("MgmtBody::Beacon");
212 self.scanner.bind(&mut self.ctx).handle_ap_advertisement(
213 bssid,
214 bcn_hdr.beacon_interval,
215 bcn_hdr.capabilities,
216 elements,
217 rx_info.clone(),
218 );
219 }
220 Some(mac::MgmtBody::ProbeResp { probe_resp_hdr, elements }) => {
221 wtrace::duration!("MgmtBody::ProbeResp");
222 self.scanner.bind(&mut self.ctx).handle_ap_advertisement(
223 bssid,
224 probe_resp_hdr.beacon_interval,
225 probe_resp_hdr.capabilities,
226 elements,
227 rx_info.clone(),
228 )
229 }
230 _ => (),
231 }
232 }
233
234 if let Some(sta) = self.sta.as_mut() {
235 match self.channel_state.get_primary() {
239 Some(main_channel) if main_channel == rx_info.primary => {
240 sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
241 .handle_mac_frame_rx(bytes, rx_info, async_id)
242 .await;
243 }
244 Some(_) => {
245 wtrace::async_end_wlansoftmac_rx(async_id, "off main channel");
246 }
247 None => {
250 error!(
251 "Received MAC frame on channel {:?} while main channel is not set.",
252 rx_info.primary
253 );
254 wtrace::async_end_wlansoftmac_rx(async_id, "main channel not set");
255 }
256 }
257 } else {
258 wtrace::async_end_wlansoftmac_rx(async_id, "no bound client");
259 }
260 }
261 fn handle_eth_frame_tx(
262 &mut self,
263 bytes: &[u8],
264 async_id: trace::Id,
265 ) -> Result<(), anyhow::Error> {
266 wtrace::duration!("ClientMlme::handle_eth_frame_tx");
267 match self.sta.as_mut() {
268 None => Err(Error::Status(
269 "Ethernet frame dropped (Client does not exist).".to_string(),
270 zx::Status::BAD_STATE,
271 )
272 .into()),
273 Some(sta) => sta
274 .bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
275 .handle_eth_frame_tx(bytes, async_id)
276 .map_err(From::from),
277 }
278 }
279 async fn handle_scan_complete(&mut self, status: Result<(), zx::Status>, scan_id: u64) {
280 self.scanner.bind(&mut self.ctx).handle_scan_complete(status, scan_id).await;
281 }
282 async fn handle_timeout(&mut self, event: TimedEvent) {
283 if let Some(sta) = self.sta.as_mut() {
284 let mut bound = sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state);
285 bound.sta.state =
286 Some(bound.sta.state.take().unwrap().on_timed_event(&mut bound, event).await);
287 }
288 }
289}
290
291impl<D> ClientMlme<D> {
292 pub fn seq_mgr(&mut self) -> &mut SequenceManager {
293 &mut self.ctx.seq_mgr
294 }
295
296 fn on_sme_get_iface_stats(
297 &self,
298 responder: wlan_sme::responder::Responder<fidl_mlme::GetIfaceStatsResponse>,
299 ) -> Result<(), Error> {
300 let resp = fidl_mlme::GetIfaceStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED);
302 responder.respond(resp);
303 Ok(())
304 }
305
306 fn on_sme_get_iface_histogram_stats(
307 &self,
308 responder: wlan_sme::responder::Responder<fidl_mlme::GetIfaceHistogramStatsResponse>,
309 ) -> Result<(), Error> {
310 let resp =
312 fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED);
313 responder.respond(resp);
314 Ok(())
315 }
316
317 fn on_sme_list_minstrel_peers(
318 &self,
319 responder: wlan_sme::responder::Responder<fidl_mlme::MinstrelListResponse>,
320 ) -> Result<(), Error> {
321 error!("ListMinstrelPeers is not supported.");
323 let peers = fidl_minstrel::Peers { addrs: vec![] };
324 let resp = fidl_mlme::MinstrelListResponse { peers };
325 responder.respond(resp);
326 Ok(())
327 }
328
329 fn on_sme_get_minstrel_stats(
330 &self,
331 responder: wlan_sme::responder::Responder<fidl_mlme::MinstrelStatsResponse>,
332 _addr: &MacAddr,
333 ) -> Result<(), Error> {
334 error!("GetMinstrelStats is not supported.");
336 let resp = fidl_mlme::MinstrelStatsResponse { peer: None };
337 responder.respond(resp);
338 Ok(())
339 }
340}
341
342impl<D: DeviceOps> ClientMlme<D> {
343 pub async fn set_main_channel(
344 &mut self,
345 primary: fidl_ieee80211::ChannelNumber,
346 bandwidth: fidl_ieee80211::ChannelBandwidth,
347 vht_secondary_80_channel: fidl_ieee80211::ChannelNumber,
348 ) -> Result<(), zx::Status> {
349 self.channel_state
350 .bind(&mut self.ctx, &mut self.scanner)
351 .set_main_channel(primary, bandwidth, vht_secondary_80_channel)
352 .await
353 }
354
355 async fn on_sme_scan(&mut self, req: fidl_mlme::ScanRequest) {
356 let txn_id = req.txn_id;
357 let _ = self.scanner.bind(&mut self.ctx).on_sme_scan(req).await.map_err(|e| {
358 error!("Scan failed in MLME: {:?}", e);
359 let code = match e {
360 Error::ScanError(scan_error) => scan_error.into(),
361 _ => fidl_mlme::ScanResultCode::InternalError,
362 };
363 self.ctx
364 .device
365 .send_mlme_event(fidl_mlme::MlmeEvent::OnScanEnd {
366 end: fidl_mlme::ScanEnd { txn_id, code },
367 })
368 .unwrap_or_else(|e| error!("error sending MLME ScanEnd: {}", e));
369 });
370 }
371
372 async fn on_sme_connect(&mut self, req: fidl_mlme::ConnectRequest) -> Result<(), Error> {
373 if let Err(e) = self.scanner.bind(&mut self.ctx).cancel_ongoing_scan().await {
376 warn!("Failed to cancel ongoing scan before connect: {}.", e);
377 }
378
379 let bssid = req.selected_bss.bssid;
380 let result = match req.selected_bss.try_into() {
381 Ok(bss) => {
382 let req = ParsedConnectRequest {
383 selected_bss: bss,
384 connect_failure_timeout: req.connect_failure_timeout,
385 auth_type: req.auth_type,
386 security_ie: req.security_ie,
387 };
388 self.join_device(&req.selected_bss).await.map(|cap| (req, cap))
389 }
390 Err(e) => Err(Error::Status(
391 format!("Error parsing BssDescription: {:?}", e),
392 zx::Status::IO_INVALID,
393 )),
394 };
395
396 match result {
397 Ok((req, client_capabilities)) => {
398 self.sta.replace(Client::new(
399 req,
400 device::try_query_iface_mac(&mut self.ctx.device).await?,
401 client_capabilities,
402 ));
403 if let Some(sta) = &mut self.sta {
404 sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
405 .start_connecting()
406 .await;
407 }
408 Ok(())
409 }
410 Err(e) => {
411 error!("Error setting up device for join: {}", e);
412 self.ctx.device.send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf {
415 resp: fidl_mlme::ConnectConfirm {
416 peer_sta_address: bssid,
417 result_code: fidl_ieee80211::StatusCode::JoinFailure,
418 association_id: 0,
419 association_ies: vec![],
420 },
421 })?;
422 Err(e)
423 }
424 }
425 }
426
427 async fn join_device(&mut self, bss: &BssDescription) -> Result<ClientCapabilities, Error> {
428 let info = ddk_converter::mlme_device_info_from_softmac(
429 device::try_query(&mut self.ctx.device).await?,
430 )?;
431 let join_caps = derive_join_capabilities(Channel::from(bss.channel), bss.rates(), &info)
432 .map_err(|e| {
433 Error::Status(
434 format!("Failed to derive join capabilities: {:?}", e),
435 zx::Status::NOT_SUPPORTED,
436 )
437 })?;
438
439 let (bandwidth, secondary80_num) = bss.channel.bandwidth.to_fidl();
440 let vht_secondary_80_channel =
441 fidl_ieee80211::ChannelNumber { band: bss.channel.band, number: secondary80_num };
442 self.set_main_channel(bss.channel.into(), bandwidth, vht_secondary_80_channel)
443 .await
444 .map_err(|status| Error::Status(format!("Error setting device channel"), status))?;
445
446 let join_bss_request = fidl_driver_common::JoinBssRequest {
447 bssid: Some(bss.bssid.to_array()),
448 bss_type: Some(fidl_ieee80211::BssType::Infrastructure),
449 remote: Some(true),
450 beacon_period: Some(bss.beacon_period),
451 ..Default::default()
452 };
453
454 self.ctx
456 .device
457 .join_bss(&join_bss_request)
458 .await
459 .map(|()| join_caps)
460 .map_err(|status| Error::Status(format!("Error setting BSS in driver"), status))
461 }
462
463 async fn on_sme_query_device_info(
464 &mut self,
465 responder: wlan_sme::responder::Responder<fidl_mlme::DeviceInfo>,
466 ) -> Result<(), Error> {
467 let info = ddk_converter::mlme_device_info_from_softmac(
468 device::try_query(&mut self.ctx.device).await?,
469 )?;
470 responder.respond(info);
471 Ok(())
472 }
473
474 async fn on_sme_query_mac_sublayer_support(
475 &mut self,
476 responder: wlan_sme::responder::Responder<fidl_common::MacSublayerSupport>,
477 ) -> Result<(), Error> {
478 let support = device::try_query_mac_sublayer_support(&mut self.ctx.device).await?;
479 responder.respond(support);
480 Ok(())
481 }
482
483 async fn on_sme_query_security_support(
484 &mut self,
485 responder: wlan_sme::responder::Responder<fidl_common::SecuritySupport>,
486 ) -> Result<(), Error> {
487 let support = device::try_query_security_support(&mut self.ctx.device).await?;
488 responder.respond(support);
489 Ok(())
490 }
491
492 async fn on_sme_query_spectrum_management_support(
493 &mut self,
494 responder: wlan_sme::responder::Responder<fidl_common::SpectrumManagementSupport>,
495 ) -> Result<(), Error> {
496 let support = device::try_query_spectrum_management_support(&mut self.ctx.device).await?;
497 responder.respond(support);
498 Ok(())
499 }
500
501 fn on_sme_get_signal_report(
502 &mut self,
503 responder: wlan_sme::responder::Responder<fidl_mlme::MlmeGetSignalReportResult>,
504 ) {
505 let report = match self.sta.as_mut() {
506 Some(sta) => sta
507 .bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
508 .get_signal_report(),
509 None => fidl_stats::SignalReport::default(),
510 };
511 responder.respond(Ok(report));
512 }
513}
514
515pub struct ParsedAssociateResp {
516 pub association_id: u16,
517 pub capabilities: CapabilityInfo,
518 pub rates: Vec<ie::SupportedRate>,
519 pub ht_cap: Option<ie::HtCapabilities>,
520 pub vht_cap: Option<ie::VhtCapabilities>,
521}
522
523impl ParsedAssociateResp {
524 pub fn parse<B: SplitByteSlice>(assoc_resp_frame: &mac::AssocRespFrame<B>) -> Self {
525 let mut parsed = ParsedAssociateResp {
526 association_id: assoc_resp_frame.assoc_resp_hdr.aid,
527 capabilities: assoc_resp_frame.assoc_resp_hdr.capabilities,
528 rates: vec![],
529 ht_cap: None,
530 vht_cap: None,
531 };
532 for (id, body) in assoc_resp_frame.ies() {
533 match id {
534 Id::SUPPORTED_RATES => match ie::parse_supported_rates(body) {
535 Err(e) => warn!("invalid Supported Rates: {}", e),
536 Ok(supported_rates) => {
537 parsed.rates.extend(supported_rates.iter());
539 }
540 },
541 Id::EXTENDED_SUPPORTED_RATES => match ie::parse_extended_supported_rates(body) {
542 Err(e) => warn!("invalid Extended Supported Rates: {}", e),
543 Ok(supported_rates) => {
544 parsed.rates.extend(supported_rates.iter());
546 }
547 },
548 Id::HT_CAPABILITIES => match ie::parse_ht_capabilities(body) {
549 Err(e) => warn!("invalid HT Capabilities: {}", e),
550 Ok(ht_cap) => {
551 parsed.ht_cap = Some(*ht_cap);
552 }
553 },
554 Id::VHT_CAPABILITIES => match ie::parse_vht_capabilities(body) {
555 Err(e) => warn!("invalid VHT Capabilities: {}", e),
556 Ok(vht_cap) => {
557 parsed.vht_cap = Some(*vht_cap);
558 }
559 },
560 _ => {}
562 }
563 }
564 parsed
565 }
566}
567
568#[cfg(test)]
569mod tests {
570 use super::state::DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT;
571 use super::*;
572 use crate::MlmeImpl;
573 use crate::client::test_utils::*;
574 use crate::device::{FakeDevice, LinkStatus, test_utils};
575 use crate::test_utils::MockWlanRxInfo;
576 use assert_matches::assert_matches;
577 use fidl_fuchsia_wlan_common as fidl_common;
578 use fidl_fuchsia_wlan_internal as fidl_internal;
579 use fidl_fuchsia_wlan_mlme as fidl_mlme;
580 use ieee80211::Ssid;
581 use wlan_common::channel::Bandwidth;
582 use wlan_common::fake_fidl_bss_description;
583 use wlan_sme::responder::Responder;
584
585 #[fuchsia::test(allow_stalls = false)]
586 async fn spawns_new_sta_on_connect_request_from_sme() {
587 let mut m = MockObjects::new().await;
588 let mut me = m.make_mlme().await;
589 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
590 me.on_sme_connect(fidl_mlme::ConnectRequest {
591 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
592 connect_failure_timeout: 100,
593 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
594 sae_password: vec![],
595 wep_key: None,
596 security_ie: vec![],
597 owe_public_key: None,
598 })
599 .await
600 .expect("valid ConnectRequest should be handled successfully");
601 me.get_bound_client().expect("client sta should have been created by now.");
602 }
603
604 #[fuchsia::test(allow_stalls = false)]
605 async fn fails_to_connect_if_channel_unknown() {
606 let mut m = MockObjects::new().await;
607 let mut me = m.make_mlme().await;
608 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
609 let mut req = fidl_mlme::ConnectRequest {
610 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
611 connect_failure_timeout: 100,
612 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
613 sae_password: vec![],
614 wep_key: None,
615 security_ie: vec![],
616 owe_public_key: None,
617 };
618
619 req.selected_bss.bandwidth = fidl_fuchsia_wlan_ieee80211::ChannelBandwidth::unknown();
620 me.on_sme_connect(req)
621 .await
622 .expect_err("ConnectRequest with unknown channel should be rejected");
623 assert!(me.get_bound_client().is_none());
624 }
625
626 async fn handle_association_status_checks_and_signal_reports(
636 mock_objects: &mut MockObjects,
637 mlme: &mut ClientMlme<FakeDevice>,
638 beacon_count: u32,
639 ) {
640 for _ in 0..beacon_count / super::state::ASSOCIATION_STATUS_TIMEOUT_BEACON_COUNT {
641 let (_, timed_event, _) =
642 mock_objects.time_stream.try_recv().expect("Should have scheduled a timed event");
643 mlme.handle_timeout(timed_event.event).await;
644 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 0);
645 mock_objects
646 .fake_device_state
647 .lock()
648 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
649 .expect("error reading SignalReport.indication");
650 }
651 }
652
653 #[fuchsia::test(allow_stalls = false)]
654 async fn test_auto_deauth_uninterrupted_interval() {
655 let mut mock_objects = MockObjects::new().await;
656 let mut mlme = mock_objects.make_mlme().await;
657 mlme.make_client_station();
658 let mut client = mlme.get_bound_client().expect("client should be present");
659
660 client.move_to_associated_state();
661
662 handle_association_status_checks_and_signal_reports(
664 &mut mock_objects,
665 &mut mlme,
666 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
667 )
668 .await;
669
670 let (_, timed_event, _) =
672 mock_objects.time_stream.try_recv().expect("Should have scheduled a timed event");
673
674 mlme.handle_timeout(timed_event.event).await;
676 mock_objects
677 .fake_device_state
678 .lock()
679 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
680 .expect("error reading SignalReport.indication");
681 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
682 #[rustfmt::skip]
683 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
684 0b1100_00_00, 0b00000000, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 3, 0, ][..]);
693 let deauth_ind = mock_objects
694 .fake_device_state
695 .lock()
696 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
697 .expect("error reading DEAUTHENTICATE.indication");
698 assert_eq!(
699 deauth_ind,
700 fidl_mlme::DeauthenticateIndication {
701 peer_sta_address: BSSID.to_array(),
702 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
703 locally_initiated: true,
704 }
705 );
706 }
707
708 #[fuchsia::test(allow_stalls = false)]
709 async fn test_auto_deauth_received_beacon() {
710 let mut mock_objects = MockObjects::new().await;
711 let mut mlme = mock_objects.make_mlme().await;
712 mlme.make_client_station();
713 let mut client = mlme.get_bound_client().expect("client should be present");
714
715 client.move_to_associated_state();
716
717 handle_association_status_checks_and_signal_reports(
719 &mut mock_objects,
720 &mut mlme,
721 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
722 )
723 .await;
724
725 let main_channel = mlme.channel_state.get_primary().unwrap();
728 mlme.handle_mac_frame_rx(
729 BEACON_FRAME,
730 fidl_softmac::WlanRxInfo {
731 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
732 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
733 phy: fidl_ieee80211::WlanPhyType::Dsss,
734 data_rate: 0,
735 primary: main_channel,
736 mcs: 0,
737 rssi_dbm: 0,
738 snr_dbh: 0,
739 bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
740 vht_secondary_80_channel: fidl_ieee80211::ChannelNumber {
741 band: main_channel.band,
742 number: 0,
743 },
744 },
745 0.into(),
746 )
747 .await;
748
749 handle_association_status_checks_and_signal_reports(
751 &mut mock_objects,
752 &mut mlme,
753 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
754 )
755 .await;
756
757 let (_, timed_event2, _) =
759 mock_objects.time_stream.try_recv().expect("Should have scheduled a timed event");
760
761 mlme.handle_timeout(timed_event2.event).await;
763 mock_objects
764 .fake_device_state
765 .lock()
766 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
767 .expect("error reading SignalReport.indication");
768 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
769 #[rustfmt::skip]
770 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
771 0b1100_00_00, 0b00000000, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 3, 0, ][..]);
780 let deauth_ind = mock_objects
781 .fake_device_state
782 .lock()
783 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
784 .expect("error reading DEAUTHENTICATE.indication");
785 assert_eq!(
786 deauth_ind,
787 fidl_mlme::DeauthenticateIndication {
788 peer_sta_address: BSSID.to_array(),
789 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
790 locally_initiated: true,
791 }
792 );
793 }
794
795 #[fuchsia::test(allow_stalls = false)]
796 async fn client_send_scan_end_on_mlme_scan_busy() {
797 let mut m = MockObjects::new().await;
798 let mut me = m.make_mlme().await;
799 me.make_client_station();
800
801 me.on_sme_scan(scan_req()).await;
803 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
804
805 let scan_end = m
806 .fake_device_state
807 .lock()
808 .next_mlme_msg::<fidl_mlme::ScanEnd>()
809 .expect("error reading MLME ScanEnd");
810 assert_eq!(
811 scan_end,
812 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
813 );
814 }
815
816 #[fuchsia::test(allow_stalls = false)]
817 async fn client_send_scan_end_on_scan_busy() {
818 let mut m = MockObjects::new().await;
819 let mut me = m.make_mlme().await;
820 me.make_client_station();
821
822 me.on_sme_scan(scan_req()).await;
824 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
825
826 let scan_end = m
827 .fake_device_state
828 .lock()
829 .next_mlme_msg::<fidl_mlme::ScanEnd>()
830 .expect("error reading MLME ScanEnd");
831 assert_eq!(
832 scan_end,
833 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
834 );
835 }
836
837 #[fuchsia::test(allow_stalls = false)]
838 async fn client_send_scan_end_on_mlme_scan_invalid_args() {
839 let mut m = MockObjects::new().await;
840 let mut me = m.make_mlme().await;
841
842 me.make_client_station();
843 me.on_sme_scan(fidl_mlme::ScanRequest {
844 txn_id: 1337,
845 scan_type: fidl_mlme::ScanTypes::Passive,
846 channel_list: vec![], ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
848 probe_delay: 0,
849 min_channel_time: 100,
850 max_channel_time: 300,
851 })
852 .await;
853 let scan_end = m
854 .fake_device_state
855 .lock()
856 .next_mlme_msg::<fidl_mlme::ScanEnd>()
857 .expect("error reading MLME ScanEnd");
858 assert_eq!(
859 scan_end,
860 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
861 );
862 }
863
864 #[fuchsia::test(allow_stalls = false)]
865 async fn client_send_scan_end_on_scan_invalid_args() {
866 let mut m = MockObjects::new().await;
867 let mut me = m.make_mlme().await;
868
869 me.make_client_station();
870 me.on_sme_scan(fidl_mlme::ScanRequest {
871 txn_id: 1337,
872 scan_type: fidl_mlme::ScanTypes::Passive,
873 channel_list: vec![fidl_ieee80211::ChannelNumber {
874 band: fidl_ieee80211::WlanBand::TwoGhz,
875 number: 6,
876 }],
877 ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
878 probe_delay: 0,
879 min_channel_time: 300, max_channel_time: 100,
881 })
882 .await;
883 let scan_end = m
884 .fake_device_state
885 .lock()
886 .next_mlme_msg::<fidl_mlme::ScanEnd>()
887 .expect("error reading MLME ScanEnd");
888 assert_eq!(
889 scan_end,
890 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
891 );
892 }
893
894 #[fuchsia::test(allow_stalls = false)]
895 async fn client_send_scan_end_on_passive_scan_fails() {
896 let mut m = MockObjects::new().await;
897 m.fake_device_state.lock().config.start_passive_scan_fails = true;
898 let mut me = m.make_mlme().await;
899
900 me.make_client_station();
901 me.on_sme_scan(scan_req()).await;
902 let scan_end = m
903 .fake_device_state
904 .lock()
905 .next_mlme_msg::<fidl_mlme::ScanEnd>()
906 .expect("error reading MLME ScanEnd");
907 assert_eq!(
908 scan_end,
909 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::NotSupported }
910 );
911 }
912
913 #[fuchsia::test(allow_stalls = false)]
914 async fn mlme_respond_to_query_device_info() {
915 let mut mock_objects = MockObjects::new().await;
916 let mut mlme = mock_objects.make_mlme().await;
917
918 let (responder, receiver) = Responder::new();
919 mlme.handle_mlme_request(wlan_sme::MlmeRequest::QueryDeviceInfo(responder))
920 .await
921 .expect("Failed to send MlmeRequest::Connect");
922 assert_eq!(
923 receiver.await.unwrap(),
924 fidl_mlme::DeviceInfo {
925 sta_addr: IFACE_MAC.to_array(),
926 factory_addr: IFACE_MAC.to_array(),
927 role: fidl_common::WlanMacRole::Client,
928 bands: test_utils::fake_mlme_band_caps(),
929 softmac_hardware_capability: 0,
930 qos_capable: false,
931 }
932 );
933 }
934
935 #[fuchsia::test(allow_stalls = false)]
936 async fn mlme_respond_to_query_mac_sublayer_support() {
937 let mut m = MockObjects::new().await;
938 let mut me = m.make_mlme().await;
939
940 let (responder, receiver) = Responder::new();
941 me.handle_mlme_request(wlan_sme::MlmeRequest::QueryMacSublayerSupport(responder))
942 .await
943 .expect("Failed to send MlmeRequest::Connect");
944 let resp = receiver.await.unwrap();
945 assert_eq!(resp.rate_selection_offload.unwrap().supported, Some(false));
946 assert_eq!(
947 resp.data_plane.unwrap().data_plane_type,
948 Some(fidl_common::DataPlaneType::EthernetDevice)
949 );
950 assert_eq!(resp.device.as_ref().unwrap().is_synthetic, Some(true));
951 assert_eq!(
952 resp.device.as_ref().unwrap().mac_implementation_type,
953 Some(fidl_common::MacImplementationType::Softmac)
954 );
955 assert_eq!(resp.device.unwrap().tx_status_report_supported, Some(true));
956 }
957
958 #[fuchsia::test(allow_stalls = false)]
959 async fn mlme_respond_to_query_security_support() {
960 let mut m = MockObjects::new().await;
961 let mut me = m.make_mlme().await;
962
963 let (responder, receiver) = Responder::new();
964 assert_matches!(
965 me.handle_mlme_request(wlan_sme::MlmeRequest::QuerySecuritySupport(responder)).await,
966 Ok(())
967 );
968 let resp = receiver.await.unwrap();
969 assert_eq!(resp.mfp.unwrap().supported, Some(false));
970 assert_eq!(resp.sae.as_ref().unwrap().driver_handler_supported, Some(false));
971 assert_eq!(resp.sae.unwrap().sme_handler_supported, Some(false));
972 }
973
974 #[fuchsia::test(allow_stalls = false)]
975 async fn mlme_respond_to_query_spectrum_management_support() {
976 let mut m = MockObjects::new().await;
977 let mut me = m.make_mlme().await;
978
979 let (responder, receiver) = Responder::new();
980 me.handle_mlme_request(wlan_sme::MlmeRequest::QuerySpectrumManagementSupport(responder))
981 .await
982 .expect("Failed to send MlmeRequest::QuerySpectrumManagementSupport");
983 assert_eq!(receiver.await.unwrap().dfs.unwrap().supported, Some(true));
984 }
985
986 #[fuchsia::test(allow_stalls = false)]
987 async fn mlme_connect_unprotected_happy_path() {
988 let mut m = MockObjects::new().await;
989 let mut me = m.make_mlme().await;
990 let channel = Channel::new(6, Bandwidth::Cbw40, fidl_ieee80211::WlanBand::TwoGhz);
991 let connect_req = fidl_mlme::ConnectRequest {
992 selected_bss: fake_fidl_bss_description!(Open,
993 ssid: Ssid::try_from("ssid").unwrap().into(),
994 bssid: BSSID.to_array(),
995 channel: channel.clone(),
996 ),
997 connect_failure_timeout: 100,
998 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
999 sae_password: vec![],
1000 wep_key: None,
1001 security_ie: vec![],
1002 owe_public_key: None,
1003 };
1004 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1005 .await
1006 .expect("Failed to send MlmeRequest::Connect");
1007
1008 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
1010 assert_eq!(ids.len(), 1);
1011 });
1012
1013 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1015 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1016 #[rustfmt::skip]
1017 let expected = vec![
1018 0b1011_00_00, 0b00000000, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 0, 0, 1, 0, 0, 0, ];
1030 assert_eq!(&frame[..], &expected[..]);
1031
1032 #[rustfmt::skip]
1034 let auth_resp_success = vec![
1035 0b1011_00_00, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 0, 0, 2, 0, 0, 0, ];
1047 me.handle_mac_frame_rx(
1048 &auth_resp_success[..],
1049 MockWlanRxInfo::with_channel(channel.into()).into(),
1050 0.into(),
1051 )
1052 .await;
1053
1054 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1056 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1057 #[rustfmt::skip]
1058 let expected = vec![
1059 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x20, 0, 0x01, 0x00, 0, 0, 0, 4, 0x73, 0x73, 0x69, 0x64, 1, 8, 2, 4, 11, 22, 12, 18, 24, 36, 50, 4, 48, 72, 96, 108, 45, 26, 0x63, 0, 0x17, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
1081 assert_eq!(&frame[..], &expected[..]);
1082
1083 #[rustfmt::skip]
1085 let assoc_resp_success = vec![
1086 0b0001_00_00, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x20, 0, 0, 0, 0, 0, 42, 0, 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
1100 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1104 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ];
1108 me.handle_mac_frame_rx(
1109 &assoc_resp_success[..],
1110 MockWlanRxInfo::with_channel(channel.into()).into(),
1111 0.into(),
1112 )
1113 .await;
1114
1115 let msg = m
1117 .fake_device_state
1118 .lock()
1119 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1120 .expect("expect ConnectConf");
1121 assert_eq!(
1122 msg,
1123 fidl_mlme::ConnectConfirm {
1124 peer_sta_address: BSSID.to_array(),
1125 result_code: fidl_ieee80211::StatusCode::Success,
1126 association_id: 42,
1127 association_ies: vec![
1128 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
1131 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1135 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
1139 }
1140 );
1141
1142 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
1144 }
1145
1146 #[fuchsia::test(allow_stalls = false)]
1147 async fn mlme_connect_protected_happy_path() {
1148 let mut m = MockObjects::new().await;
1149 let mut me = m.make_mlme().await;
1150 let channel = Channel::new(6, Bandwidth::Cbw40, fidl_ieee80211::WlanBand::TwoGhz);
1151 let connect_req = fidl_mlme::ConnectRequest {
1152 selected_bss: fake_fidl_bss_description!(Wpa2,
1153 ssid: Ssid::try_from("ssid").unwrap().into(),
1154 bssid: BSSID.to_array(),
1155 channel: channel.clone(),
1156 ),
1157 connect_failure_timeout: 100,
1158 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1159 sae_password: vec![],
1160 wep_key: None,
1161 security_ie: vec![
1162 48, 18, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 2, ],
1168 owe_public_key: None,
1169 };
1170 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1171 .await
1172 .expect("Failed to send MlmeRequest::Connect");
1173
1174 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
1176 assert_eq!(ids.len(), 1);
1177 });
1178
1179 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1181 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1182 #[rustfmt::skip]
1183 let expected = vec![
1184 0b1011_00_00, 0b00000000, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 0, 0, 1, 0, 0, 0, ];
1196 assert_eq!(&frame[..], &expected[..]);
1197
1198 #[rustfmt::skip]
1200 let auth_resp_success = vec![
1201 0b1011_00_00, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 0, 0, 2, 0, 0, 0, ];
1213 me.handle_mac_frame_rx(
1214 &auth_resp_success[..],
1215 MockWlanRxInfo::with_channel(channel.into()).into(),
1216 0.into(),
1217 )
1218 .await;
1219
1220 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1222 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1223 #[rustfmt::skip]
1224 let expected = vec![
1225 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x20, 0, 0x01, 0x00, 0, 0, 0, 4, 0x73, 0x73, 0x69, 0x64, 1, 8, 2, 4, 11, 22, 12, 18, 24, 36, 50, 4, 48, 72, 96, 108, 48, 18, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 2, 45, 26, 0x63, 0, 0x17, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
1252 assert_eq!(&frame[..], &expected[..]);
1253
1254 #[rustfmt::skip]
1256 let assoc_resp_success = vec![
1257 0b0001_00_00, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x20, 0, 0, 0, 0, 0, 42, 0, 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
1271 0x30, 18, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 2, 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ];
1284 me.handle_mac_frame_rx(
1285 &assoc_resp_success[..],
1286 MockWlanRxInfo::with_channel(channel.into()).into(),
1287 0.into(),
1288 )
1289 .await;
1290
1291 let msg = m
1293 .fake_device_state
1294 .lock()
1295 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1296 .expect("expect ConnectConf");
1297 assert_eq!(
1298 msg,
1299 fidl_mlme::ConnectConfirm {
1300 peer_sta_address: BSSID.to_array(),
1301 result_code: fidl_ieee80211::StatusCode::Success,
1302 association_id: 42,
1303 association_ies: vec![
1304 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 18, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 2, 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1315 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
1320 }
1321 );
1322
1323 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::DOWN);
1325
1326 me.handle_mlme_request(wlan_sme::MlmeRequest::SetCtrlPort(
1328 fidl_mlme::SetControlledPortRequest {
1329 peer_sta_address: BSSID.to_array(),
1330 state: fidl_mlme::ControlledPortState::Open,
1331 },
1332 ))
1333 .await
1334 .expect("expect sending msg to succeed");
1335
1336 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
1338 }
1339
1340 #[fuchsia::test(allow_stalls = false)]
1341 async fn mlme_connect_vht() {
1342 let mut m = MockObjects::new().await;
1343 let mut me = m.make_mlme().await;
1344 let channel = Channel::new(36, Bandwidth::Cbw40, fidl_ieee80211::WlanBand::FiveGhz);
1345 let connect_req = fidl_mlme::ConnectRequest {
1346 selected_bss: fake_fidl_bss_description!(Open,
1347 ssid: Ssid::try_from("ssid").unwrap().into(),
1348 bssid: BSSID.to_array(),
1349 channel: channel.clone(),
1350 ),
1351 connect_failure_timeout: 100,
1352 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1353 sae_password: vec![],
1354 wep_key: None,
1355 security_ie: vec![],
1356 owe_public_key: None,
1357 };
1358 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1359 .await
1360 .expect("Failed to send MlmeRequest::Connect.");
1361
1362 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
1364 assert_eq!(ids.len(), 1);
1365 });
1366
1367 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1369 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1370
1371 #[rustfmt::skip]
1373 let auth_resp_success = vec![
1374 0b1011_00_00, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 0, 0, 2, 0, 0, 0, ];
1386 me.handle_mac_frame_rx(
1387 &auth_resp_success[..],
1388 MockWlanRxInfo::with_channel(channel.into()).into(),
1389 0.into(),
1390 )
1391 .await;
1392
1393 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1395 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1396 #[rustfmt::skip]
1397 let expected = vec![
1398 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x20, 0, 0x01, 0x00, 0, 0, 0, 4, 0x73, 0x73, 0x69, 0x64, 1, 6, 2, 4, 11, 22, 48, 96, 45, 26, 0x63, 0, 0x17, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 12, 50, 80, 128, 15, 254, 255, 0, 0, 254, 255, 0, 0, ];
1420 assert_eq!(&frame[..], &expected[..]);
1421 }
1422
1423 #[fuchsia::test(allow_stalls = false)]
1424 async fn mlme_connect_timeout() {
1425 let mut m = MockObjects::new().await;
1426 let mut me = m.make_mlme().await;
1427 let connect_req = fidl_mlme::ConnectRequest {
1428 selected_bss: fake_fidl_bss_description!(Open, bssid: BSSID.to_array()),
1429 connect_failure_timeout: 100,
1430 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1431 sae_password: vec![],
1432 wep_key: None,
1433 security_ie: vec![],
1434 owe_public_key: None,
1435 };
1436 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1437 .await
1438 .expect("Failed to send MlmeRequest::Connect.");
1439
1440 let (event, _id) = assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(events) => {
1442 assert_eq!(events.len(), 1);
1443 events[0].clone()
1444 });
1445
1446 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1448 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1449
1450 me.handle_timeout(event).await;
1452
1453 let msg = m
1455 .fake_device_state
1456 .lock()
1457 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1458 .expect("expect msg");
1459 assert_eq!(
1460 msg,
1461 fidl_mlme::ConnectConfirm {
1462 peer_sta_address: BSSID.to_array(),
1463 result_code: fidl_ieee80211::StatusCode::RejectedSequenceTimeout,
1464 association_id: 0,
1465 association_ies: vec![],
1466 },
1467 );
1468 }
1469
1470 #[fuchsia::test(allow_stalls = false)]
1471 async fn mlme_reconnect_no_sta() {
1472 let mut m = MockObjects::new().await;
1473 let mut me = m.make_mlme().await;
1474
1475 let reconnect_req = fidl_mlme::ReconnectRequest { peer_sta_address: [1, 2, 3, 4, 5, 6] };
1476 let result = me.handle_mlme_request(wlan_sme::MlmeRequest::Reconnect(reconnect_req)).await;
1477 let err = result.unwrap_err();
1478 let mlme_err = err.downcast_ref::<Error>().expect("expected Mlme Error");
1479 assert_matches!(mlme_err, Error::Status(_, zx::Status::BAD_STATE));
1480
1481 let msg = m
1483 .fake_device_state
1484 .lock()
1485 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1486 .expect("expect msg");
1487 assert_eq!(
1488 msg,
1489 fidl_mlme::ConnectConfirm {
1490 peer_sta_address: [1, 2, 3, 4, 5, 6],
1491 result_code: fidl_ieee80211::StatusCode::DeniedNoAssociationExists,
1492 association_id: 0,
1493 association_ies: vec![],
1494 },
1495 );
1496 }
1497
1498 #[fuchsia::test(allow_stalls = false)]
1499 async fn mlme_respond_to_get_iface_stats_with_error_status() {
1500 let mut m = MockObjects::new().await;
1501 let mut me = m.make_mlme().await;
1502
1503 let (responder, receiver) = Responder::new();
1504 me.handle_mlme_request(wlan_sme::MlmeRequest::GetIfaceStats(responder))
1505 .await
1506 .expect("Failed to send MlmeRequest::GetIfaceStats.");
1507 assert_eq!(
1508 receiver.await,
1509 Ok(fidl_mlme::GetIfaceStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED))
1510 );
1511 }
1512
1513 #[fuchsia::test(allow_stalls = false)]
1514 async fn mlme_respond_to_get_iface_histogram_stats_with_error_status() {
1515 let mut m = MockObjects::new().await;
1516 let mut me = m.make_mlme().await;
1517
1518 let (responder, receiver) = Responder::new();
1519 me.handle_mlme_request(wlan_sme::MlmeRequest::GetIfaceHistogramStats(responder))
1520 .await
1521 .expect("Failed to send MlmeRequest::GetIfaceHistogramStats");
1522 assert_eq!(
1523 receiver.await,
1524 Ok(fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(
1525 zx::sys::ZX_ERR_NOT_SUPPORTED
1526 ))
1527 );
1528 }
1529
1530 #[test]
1531 fn drop_mgmt_frame_wrong_bssid() {
1532 let frame = [
1533 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0x10, 0, ];
1541 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1542 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1543 }
1544
1545 #[test]
1546 fn drop_mgmt_frame_wrong_dst_addr() {
1547 let frame = [
1548 0b11010000, 0b00000000, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1556 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1557 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1558 }
1559
1560 #[test]
1561 fn mgmt_frame_ok_broadcast() {
1562 let frame = [
1563 0b11010000, 0b00000000, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1571 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1572 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1573 }
1574
1575 #[test]
1576 fn mgmt_frame_ok_client_addr() {
1577 let frame = [
1578 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1586 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1587 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1588 }
1589
1590 #[test]
1591 fn drop_data_frame_wrong_bssid() {
1592 let frame = [
1593 0b01001000,
1595 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1602 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1603 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1604 }
1605
1606 #[test]
1607 fn drop_data_frame_wrong_dst_addr() {
1608 let frame = [
1609 0b01001000,
1611 0b00000010, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1618 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1619 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1620 }
1621
1622 #[test]
1623 fn data_frame_ok_broadcast() {
1624 let frame = [
1625 0b01001000,
1627 0b00000010, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1634 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1635 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1636 }
1637
1638 #[test]
1639 fn data_frame_ok_client_addr() {
1640 let frame = [
1641 0b01001000,
1643 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1650 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1651 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1652 }
1653}