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) if self.sta.is_none() => {
163 responder.respond(Ok(fidl_stats::SignalReport::default()));
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_main_channel(),
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_main_channel() {
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: 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 channel: fidl_ieee80211::ChannelNumber,
346 cbw: fidl_ieee80211::ChannelBandwidth,
347 secondary80: fidl_ieee80211::ChannelNumber,
348 ) -> Result<(), zx::Status> {
349 self.channel_state
350 .bind(&mut self.ctx, &mut self.scanner)
351 .set_main_channel(channel, cbw, secondary80)
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 (cbw, secondary80_num) = bss.channel.cbw.to_fidl();
440 let secondary80 =
441 fidl_ieee80211::ChannelNumber { band: bss.channel.band, number: secondary80_num };
442 self.set_main_channel(bss.channel.into(), cbw, secondary80)
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
502pub struct ParsedAssociateResp {
503 pub association_id: u16,
504 pub capabilities: CapabilityInfo,
505 pub rates: Vec<ie::SupportedRate>,
506 pub ht_cap: Option<ie::HtCapabilities>,
507 pub vht_cap: Option<ie::VhtCapabilities>,
508}
509
510impl ParsedAssociateResp {
511 pub fn parse<B: SplitByteSlice>(assoc_resp_frame: &mac::AssocRespFrame<B>) -> Self {
512 let mut parsed = ParsedAssociateResp {
513 association_id: assoc_resp_frame.assoc_resp_hdr.aid,
514 capabilities: assoc_resp_frame.assoc_resp_hdr.capabilities,
515 rates: vec![],
516 ht_cap: None,
517 vht_cap: None,
518 };
519 for (id, body) in assoc_resp_frame.ies() {
520 match id {
521 Id::SUPPORTED_RATES => match ie::parse_supported_rates(body) {
522 Err(e) => warn!("invalid Supported Rates: {}", e),
523 Ok(supported_rates) => {
524 parsed.rates.extend(supported_rates.iter());
526 }
527 },
528 Id::EXTENDED_SUPPORTED_RATES => match ie::parse_extended_supported_rates(body) {
529 Err(e) => warn!("invalid Extended Supported Rates: {}", e),
530 Ok(supported_rates) => {
531 parsed.rates.extend(supported_rates.iter());
533 }
534 },
535 Id::HT_CAPABILITIES => match ie::parse_ht_capabilities(body) {
536 Err(e) => warn!("invalid HT Capabilities: {}", e),
537 Ok(ht_cap) => {
538 parsed.ht_cap = Some(*ht_cap);
539 }
540 },
541 Id::VHT_CAPABILITIES => match ie::parse_vht_capabilities(body) {
542 Err(e) => warn!("invalid VHT Capabilities: {}", e),
543 Ok(vht_cap) => {
544 parsed.vht_cap = Some(*vht_cap);
545 }
546 },
547 _ => {}
549 }
550 }
551 parsed
552 }
553}
554
555#[cfg(test)]
556mod tests {
557 use super::state::DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT;
558 use super::*;
559 use crate::MlmeImpl;
560 use crate::client::test_utils::*;
561 use crate::device::{FakeDevice, LinkStatus, test_utils};
562 use crate::test_utils::MockWlanRxInfo;
563 use assert_matches::assert_matches;
564 use fidl_fuchsia_wlan_common as fidl_common;
565 use fidl_fuchsia_wlan_internal as fidl_internal;
566 use fidl_fuchsia_wlan_mlme as fidl_mlme;
567 use ieee80211::Ssid;
568 use wlan_common::channel::Cbw;
569 use wlan_common::fake_fidl_bss_description;
570 use wlan_sme::responder::Responder;
571
572 #[fuchsia::test(allow_stalls = false)]
573 async fn spawns_new_sta_on_connect_request_from_sme() {
574 let mut m = MockObjects::new().await;
575 let mut me = m.make_mlme().await;
576 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
577 me.on_sme_connect(fidl_mlme::ConnectRequest {
578 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
579 connect_failure_timeout: 100,
580 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
581 sae_password: vec![],
582 wep_key: None,
583 security_ie: vec![],
584 owe_public_key: None,
585 })
586 .await
587 .expect("valid ConnectRequest should be handled successfully");
588 me.get_bound_client().expect("client sta should have been created by now.");
589 }
590
591 #[fuchsia::test(allow_stalls = false)]
592 async fn fails_to_connect_if_channel_unknown() {
593 let mut m = MockObjects::new().await;
594 let mut me = m.make_mlme().await;
595 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
596 let mut req = fidl_mlme::ConnectRequest {
597 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
598 connect_failure_timeout: 100,
599 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
600 sae_password: vec![],
601 wep_key: None,
602 security_ie: vec![],
603 owe_public_key: None,
604 };
605
606 req.selected_bss.bandwidth = fidl_fuchsia_wlan_ieee80211::ChannelBandwidth::unknown();
607 me.on_sme_connect(req)
608 .await
609 .expect_err("ConnectRequest with unknown channel should be rejected");
610 assert!(me.get_bound_client().is_none());
611 }
612
613 async fn handle_association_status_checks_and_signal_reports(
623 mock_objects: &mut MockObjects,
624 mlme: &mut ClientMlme<FakeDevice>,
625 beacon_count: u32,
626 ) {
627 for _ in 0..beacon_count / super::state::ASSOCIATION_STATUS_TIMEOUT_BEACON_COUNT {
628 let (_, timed_event, _) = mock_objects
629 .time_stream
630 .try_next()
631 .unwrap()
632 .expect("Should have scheduled a timed event");
633 mlme.handle_timeout(timed_event.event).await;
634 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 0);
635 mock_objects
636 .fake_device_state
637 .lock()
638 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
639 .expect("error reading SignalReport.indication");
640 }
641 }
642
643 #[fuchsia::test(allow_stalls = false)]
644 async fn test_auto_deauth_uninterrupted_interval() {
645 let mut mock_objects = MockObjects::new().await;
646 let mut mlme = mock_objects.make_mlme().await;
647 mlme.make_client_station();
648 let mut client = mlme.get_bound_client().expect("client should be present");
649
650 client.move_to_associated_state();
651
652 handle_association_status_checks_and_signal_reports(
654 &mut mock_objects,
655 &mut mlme,
656 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
657 )
658 .await;
659
660 let (_, timed_event, _) = mock_objects
662 .time_stream
663 .try_next()
664 .unwrap()
665 .expect("Should have scheduled a timed event");
666
667 mlme.handle_timeout(timed_event.event).await;
669 mock_objects
670 .fake_device_state
671 .lock()
672 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
673 .expect("error reading SignalReport.indication");
674 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
675 #[rustfmt::skip]
676 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
677 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, ][..]);
686 let deauth_ind = mock_objects
687 .fake_device_state
688 .lock()
689 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
690 .expect("error reading DEAUTHENTICATE.indication");
691 assert_eq!(
692 deauth_ind,
693 fidl_mlme::DeauthenticateIndication {
694 peer_sta_address: BSSID.to_array(),
695 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
696 locally_initiated: true,
697 }
698 );
699 }
700
701 #[fuchsia::test(allow_stalls = false)]
702 async fn test_auto_deauth_received_beacon() {
703 let mut mock_objects = MockObjects::new().await;
704 let mut mlme = mock_objects.make_mlme().await;
705 mlme.make_client_station();
706 let mut client = mlme.get_bound_client().expect("client should be present");
707
708 client.move_to_associated_state();
709
710 handle_association_status_checks_and_signal_reports(
712 &mut mock_objects,
713 &mut mlme,
714 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
715 )
716 .await;
717
718 let main_channel = mlme.channel_state.get_main_channel().unwrap();
721 mlme.handle_mac_frame_rx(
722 BEACON_FRAME,
723 fidl_softmac::WlanRxInfo {
724 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
725 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
726 phy: fidl_ieee80211::WlanPhyType::Dsss,
727 data_rate: 0,
728 primary: main_channel,
729 mcs: 0,
730 rssi_dbm: 0,
731 snr_dbh: 0,
732 bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
733 vht_secondary_80_channel: fidl_ieee80211::ChannelNumber {
734 band: main_channel.band,
735 number: 0,
736 },
737 },
738 0.into(),
739 )
740 .await;
741
742 handle_association_status_checks_and_signal_reports(
744 &mut mock_objects,
745 &mut mlme,
746 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
747 )
748 .await;
749
750 let (_, timed_event2, _) = mock_objects
752 .time_stream
753 .try_next()
754 .unwrap()
755 .expect("Should have scheduled a timed event");
756
757 mlme.handle_timeout(timed_event2.event).await;
759 mock_objects
760 .fake_device_state
761 .lock()
762 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
763 .expect("error reading SignalReport.indication");
764 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
765 #[rustfmt::skip]
766 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
767 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, ][..]);
776 let deauth_ind = mock_objects
777 .fake_device_state
778 .lock()
779 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
780 .expect("error reading DEAUTHENTICATE.indication");
781 assert_eq!(
782 deauth_ind,
783 fidl_mlme::DeauthenticateIndication {
784 peer_sta_address: BSSID.to_array(),
785 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
786 locally_initiated: true,
787 }
788 );
789 }
790
791 #[fuchsia::test(allow_stalls = false)]
792 async fn client_send_scan_end_on_mlme_scan_busy() {
793 let mut m = MockObjects::new().await;
794 let mut me = m.make_mlme().await;
795 me.make_client_station();
796
797 me.on_sme_scan(scan_req()).await;
799 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
800
801 let scan_end = m
802 .fake_device_state
803 .lock()
804 .next_mlme_msg::<fidl_mlme::ScanEnd>()
805 .expect("error reading MLME ScanEnd");
806 assert_eq!(
807 scan_end,
808 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
809 );
810 }
811
812 #[fuchsia::test(allow_stalls = false)]
813 async fn client_send_scan_end_on_scan_busy() {
814 let mut m = MockObjects::new().await;
815 let mut me = m.make_mlme().await;
816 me.make_client_station();
817
818 me.on_sme_scan(scan_req()).await;
820 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
821
822 let scan_end = m
823 .fake_device_state
824 .lock()
825 .next_mlme_msg::<fidl_mlme::ScanEnd>()
826 .expect("error reading MLME ScanEnd");
827 assert_eq!(
828 scan_end,
829 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
830 );
831 }
832
833 #[fuchsia::test(allow_stalls = false)]
834 async fn client_send_scan_end_on_mlme_scan_invalid_args() {
835 let mut m = MockObjects::new().await;
836 let mut me = m.make_mlme().await;
837
838 me.make_client_station();
839 me.on_sme_scan(fidl_mlme::ScanRequest {
840 txn_id: 1337,
841 scan_type: fidl_mlme::ScanTypes::Passive,
842 channel_list: vec![], ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
844 probe_delay: 0,
845 min_channel_time: 100,
846 max_channel_time: 300,
847 })
848 .await;
849 let scan_end = m
850 .fake_device_state
851 .lock()
852 .next_mlme_msg::<fidl_mlme::ScanEnd>()
853 .expect("error reading MLME ScanEnd");
854 assert_eq!(
855 scan_end,
856 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
857 );
858 }
859
860 #[fuchsia::test(allow_stalls = false)]
861 async fn client_send_scan_end_on_scan_invalid_args() {
862 let mut m = MockObjects::new().await;
863 let mut me = m.make_mlme().await;
864
865 me.make_client_station();
866 me.on_sme_scan(fidl_mlme::ScanRequest {
867 txn_id: 1337,
868 scan_type: fidl_mlme::ScanTypes::Passive,
869 channel_list: vec![fidl_ieee80211::ChannelNumber {
870 band: fidl_ieee80211::WlanBand::TwoGhz,
871 number: 6,
872 }],
873 ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
874 probe_delay: 0,
875 min_channel_time: 300, max_channel_time: 100,
877 })
878 .await;
879 let scan_end = m
880 .fake_device_state
881 .lock()
882 .next_mlme_msg::<fidl_mlme::ScanEnd>()
883 .expect("error reading MLME ScanEnd");
884 assert_eq!(
885 scan_end,
886 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
887 );
888 }
889
890 #[fuchsia::test(allow_stalls = false)]
891 async fn client_send_scan_end_on_passive_scan_fails() {
892 let mut m = MockObjects::new().await;
893 m.fake_device_state.lock().config.start_passive_scan_fails = true;
894 let mut me = m.make_mlme().await;
895
896 me.make_client_station();
897 me.on_sme_scan(scan_req()).await;
898 let scan_end = m
899 .fake_device_state
900 .lock()
901 .next_mlme_msg::<fidl_mlme::ScanEnd>()
902 .expect("error reading MLME ScanEnd");
903 assert_eq!(
904 scan_end,
905 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::NotSupported }
906 );
907 }
908
909 #[fuchsia::test(allow_stalls = false)]
910 async fn mlme_respond_to_query_device_info() {
911 let mut mock_objects = MockObjects::new().await;
912 let mut mlme = mock_objects.make_mlme().await;
913
914 let (responder, receiver) = Responder::new();
915 mlme.handle_mlme_request(wlan_sme::MlmeRequest::QueryDeviceInfo(responder))
916 .await
917 .expect("Failed to send MlmeRequest::Connect");
918 assert_eq!(
919 receiver.await.unwrap(),
920 fidl_mlme::DeviceInfo {
921 sta_addr: IFACE_MAC.to_array(),
922 factory_addr: IFACE_MAC.to_array(),
923 role: fidl_common::WlanMacRole::Client,
924 bands: test_utils::fake_mlme_band_caps(),
925 softmac_hardware_capability: 0,
926 qos_capable: false,
927 }
928 );
929 }
930
931 #[fuchsia::test(allow_stalls = false)]
932 async fn mlme_respond_to_query_mac_sublayer_support() {
933 let mut m = MockObjects::new().await;
934 let mut me = m.make_mlme().await;
935
936 let (responder, receiver) = Responder::new();
937 me.handle_mlme_request(wlan_sme::MlmeRequest::QueryMacSublayerSupport(responder))
938 .await
939 .expect("Failed to send MlmeRequest::Connect");
940 let resp = receiver.await.unwrap();
941 assert_eq!(resp.rate_selection_offload.unwrap().supported, Some(false));
942 assert_eq!(
943 resp.data_plane.unwrap().data_plane_type,
944 Some(fidl_common::DataPlaneType::EthernetDevice)
945 );
946 assert_eq!(resp.device.as_ref().unwrap().is_synthetic, Some(true));
947 assert_eq!(
948 resp.device.as_ref().unwrap().mac_implementation_type,
949 Some(fidl_common::MacImplementationType::Softmac)
950 );
951 assert_eq!(resp.device.unwrap().tx_status_report_supported, Some(true));
952 }
953
954 #[fuchsia::test(allow_stalls = false)]
955 async fn mlme_respond_to_query_security_support() {
956 let mut m = MockObjects::new().await;
957 let mut me = m.make_mlme().await;
958
959 let (responder, receiver) = Responder::new();
960 assert_matches!(
961 me.handle_mlme_request(wlan_sme::MlmeRequest::QuerySecuritySupport(responder)).await,
962 Ok(())
963 );
964 let resp = receiver.await.unwrap();
965 assert_eq!(resp.mfp.unwrap().supported, Some(false));
966 assert_eq!(resp.sae.as_ref().unwrap().driver_handler_supported, Some(false));
967 assert_eq!(resp.sae.unwrap().sme_handler_supported, Some(false));
968 }
969
970 #[fuchsia::test(allow_stalls = false)]
971 async fn mlme_respond_to_query_spectrum_management_support() {
972 let mut m = MockObjects::new().await;
973 let mut me = m.make_mlme().await;
974
975 let (responder, receiver) = Responder::new();
976 me.handle_mlme_request(wlan_sme::MlmeRequest::QuerySpectrumManagementSupport(responder))
977 .await
978 .expect("Failed to send MlmeRequest::QuerySpectrumManagementSupport");
979 assert_eq!(receiver.await.unwrap().dfs.unwrap().supported, Some(true));
980 }
981
982 #[fuchsia::test(allow_stalls = false)]
983 async fn mlme_connect_unprotected_happy_path() {
984 let mut m = MockObjects::new().await;
985 let mut me = m.make_mlme().await;
986 let channel = Channel::new(6, Cbw::Cbw40, fidl_ieee80211::WlanBand::TwoGhz);
987 let connect_req = fidl_mlme::ConnectRequest {
988 selected_bss: fake_fidl_bss_description!(Open,
989 ssid: Ssid::try_from("ssid").unwrap().into(),
990 bssid: BSSID.to_array(),
991 channel: channel.clone(),
992 ),
993 connect_failure_timeout: 100,
994 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
995 sae_password: vec![],
996 wep_key: None,
997 security_ie: vec![],
998 owe_public_key: None,
999 };
1000 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1001 .await
1002 .expect("Failed to send MlmeRequest::Connect");
1003
1004 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
1006 assert_eq!(ids.len(), 1);
1007 });
1008
1009 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1011 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1012 #[rustfmt::skip]
1013 let expected = vec![
1014 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, ];
1026 assert_eq!(&frame[..], &expected[..]);
1027
1028 #[rustfmt::skip]
1030 let auth_resp_success = vec![
1031 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, ];
1043 me.handle_mac_frame_rx(
1044 &auth_resp_success[..],
1045 MockWlanRxInfo::with_channel(channel.into()).into(),
1046 0.into(),
1047 )
1048 .await;
1049
1050 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1052 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1053 #[rustfmt::skip]
1054 let expected = vec![
1055 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, ];
1077 assert_eq!(&frame[..], &expected[..]);
1078
1079 #[rustfmt::skip]
1081 let assoc_resp_success = vec![
1082 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,
1096 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1100 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ];
1104 me.handle_mac_frame_rx(
1105 &assoc_resp_success[..],
1106 MockWlanRxInfo::with_channel(channel.into()).into(),
1107 0.into(),
1108 )
1109 .await;
1110
1111 let msg = m
1113 .fake_device_state
1114 .lock()
1115 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1116 .expect("expect ConnectConf");
1117 assert_eq!(
1118 msg,
1119 fidl_mlme::ConnectConfirm {
1120 peer_sta_address: BSSID.to_array(),
1121 result_code: fidl_ieee80211::StatusCode::Success,
1122 association_id: 42,
1123 association_ies: vec![
1124 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
1127 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1131 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
1135 }
1136 );
1137
1138 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
1140 }
1141
1142 #[fuchsia::test(allow_stalls = false)]
1143 async fn mlme_connect_protected_happy_path() {
1144 let mut m = MockObjects::new().await;
1145 let mut me = m.make_mlme().await;
1146 let channel = Channel::new(6, Cbw::Cbw40, fidl_ieee80211::WlanBand::TwoGhz);
1147 let connect_req = fidl_mlme::ConnectRequest {
1148 selected_bss: fake_fidl_bss_description!(Wpa2,
1149 ssid: Ssid::try_from("ssid").unwrap().into(),
1150 bssid: BSSID.to_array(),
1151 channel: channel.clone(),
1152 ),
1153 connect_failure_timeout: 100,
1154 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1155 sae_password: vec![],
1156 wep_key: None,
1157 security_ie: vec![
1158 48, 18, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 2, ],
1164 owe_public_key: None,
1165 };
1166 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1167 .await
1168 .expect("Failed to send MlmeRequest::Connect");
1169
1170 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
1172 assert_eq!(ids.len(), 1);
1173 });
1174
1175 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1177 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1178 #[rustfmt::skip]
1179 let expected = vec![
1180 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, ];
1192 assert_eq!(&frame[..], &expected[..]);
1193
1194 #[rustfmt::skip]
1196 let auth_resp_success = vec![
1197 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, ];
1209 me.handle_mac_frame_rx(
1210 &auth_resp_success[..],
1211 MockWlanRxInfo::with_channel(channel.into()).into(),
1212 0.into(),
1213 )
1214 .await;
1215
1216 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1218 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1219 #[rustfmt::skip]
1220 let expected = vec![
1221 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, ];
1248 assert_eq!(&frame[..], &expected[..]);
1249
1250 #[rustfmt::skip]
1252 let assoc_resp_success = vec![
1253 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,
1267 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, ];
1280 me.handle_mac_frame_rx(
1281 &assoc_resp_success[..],
1282 MockWlanRxInfo::with_channel(channel.into()).into(),
1283 0.into(),
1284 )
1285 .await;
1286
1287 let msg = m
1289 .fake_device_state
1290 .lock()
1291 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1292 .expect("expect ConnectConf");
1293 assert_eq!(
1294 msg,
1295 fidl_mlme::ConnectConfirm {
1296 peer_sta_address: BSSID.to_array(),
1297 result_code: fidl_ieee80211::StatusCode::Success,
1298 association_id: 42,
1299 association_ies: vec![
1300 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,
1311 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
1316 }
1317 );
1318
1319 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::DOWN);
1321
1322 me.handle_mlme_request(wlan_sme::MlmeRequest::SetCtrlPort(
1324 fidl_mlme::SetControlledPortRequest {
1325 peer_sta_address: BSSID.to_array(),
1326 state: fidl_mlme::ControlledPortState::Open,
1327 },
1328 ))
1329 .await
1330 .expect("expect sending msg to succeed");
1331
1332 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
1334 }
1335
1336 #[fuchsia::test(allow_stalls = false)]
1337 async fn mlme_connect_vht() {
1338 let mut m = MockObjects::new().await;
1339 let mut me = m.make_mlme().await;
1340 let channel = Channel::new(36, Cbw::Cbw40, fidl_ieee80211::WlanBand::FiveGhz);
1341 let connect_req = fidl_mlme::ConnectRequest {
1342 selected_bss: fake_fidl_bss_description!(Open,
1343 ssid: Ssid::try_from("ssid").unwrap().into(),
1344 bssid: BSSID.to_array(),
1345 channel: channel.clone(),
1346 ),
1347 connect_failure_timeout: 100,
1348 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1349 sae_password: vec![],
1350 wep_key: None,
1351 security_ie: vec![],
1352 owe_public_key: None,
1353 };
1354 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1355 .await
1356 .expect("Failed to send MlmeRequest::Connect.");
1357
1358 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
1360 assert_eq!(ids.len(), 1);
1361 });
1362
1363 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1365 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1366
1367 #[rustfmt::skip]
1369 let auth_resp_success = vec![
1370 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, ];
1382 me.handle_mac_frame_rx(
1383 &auth_resp_success[..],
1384 MockWlanRxInfo::with_channel(channel.into()).into(),
1385 0.into(),
1386 )
1387 .await;
1388
1389 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1391 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1392 #[rustfmt::skip]
1393 let expected = vec![
1394 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, ];
1416 assert_eq!(&frame[..], &expected[..]);
1417 }
1418
1419 #[fuchsia::test(allow_stalls = false)]
1420 async fn mlme_connect_timeout() {
1421 let mut m = MockObjects::new().await;
1422 let mut me = m.make_mlme().await;
1423 let connect_req = fidl_mlme::ConnectRequest {
1424 selected_bss: fake_fidl_bss_description!(Open, bssid: BSSID.to_array()),
1425 connect_failure_timeout: 100,
1426 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1427 sae_password: vec![],
1428 wep_key: None,
1429 security_ie: vec![],
1430 owe_public_key: None,
1431 };
1432 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1433 .await
1434 .expect("Failed to send MlmeRequest::Connect.");
1435
1436 let (event, _id) = assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(events) => {
1438 assert_eq!(events.len(), 1);
1439 events[0].clone()
1440 });
1441
1442 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1444 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1445
1446 me.handle_timeout(event).await;
1448
1449 let msg = m
1451 .fake_device_state
1452 .lock()
1453 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1454 .expect("expect msg");
1455 assert_eq!(
1456 msg,
1457 fidl_mlme::ConnectConfirm {
1458 peer_sta_address: BSSID.to_array(),
1459 result_code: fidl_ieee80211::StatusCode::RejectedSequenceTimeout,
1460 association_id: 0,
1461 association_ies: vec![],
1462 },
1463 );
1464 }
1465
1466 #[fuchsia::test(allow_stalls = false)]
1467 async fn mlme_reconnect_no_sta() {
1468 let mut m = MockObjects::new().await;
1469 let mut me = m.make_mlme().await;
1470
1471 let reconnect_req = fidl_mlme::ReconnectRequest { peer_sta_address: [1, 2, 3, 4, 5, 6] };
1472 let result = me.handle_mlme_request(wlan_sme::MlmeRequest::Reconnect(reconnect_req)).await;
1473 let err = result.unwrap_err();
1474 let mlme_err = err.downcast_ref::<Error>().expect("expected Mlme Error");
1475 assert_matches!(mlme_err, Error::Status(_, zx::Status::BAD_STATE));
1476
1477 let msg = m
1479 .fake_device_state
1480 .lock()
1481 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1482 .expect("expect msg");
1483 assert_eq!(
1484 msg,
1485 fidl_mlme::ConnectConfirm {
1486 peer_sta_address: [1, 2, 3, 4, 5, 6],
1487 result_code: fidl_ieee80211::StatusCode::DeniedNoAssociationExists,
1488 association_id: 0,
1489 association_ies: vec![],
1490 },
1491 );
1492 }
1493
1494 #[fuchsia::test(allow_stalls = false)]
1495 async fn mlme_respond_to_get_iface_stats_with_error_status() {
1496 let mut m = MockObjects::new().await;
1497 let mut me = m.make_mlme().await;
1498
1499 let (responder, receiver) = Responder::new();
1500 me.handle_mlme_request(wlan_sme::MlmeRequest::GetIfaceStats(responder))
1501 .await
1502 .expect("Failed to send MlmeRequest::GetIfaceStats.");
1503 assert_eq!(
1504 receiver.await,
1505 Ok(fidl_mlme::GetIfaceStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED))
1506 );
1507 }
1508
1509 #[fuchsia::test(allow_stalls = false)]
1510 async fn mlme_respond_to_get_iface_histogram_stats_with_error_status() {
1511 let mut m = MockObjects::new().await;
1512 let mut me = m.make_mlme().await;
1513
1514 let (responder, receiver) = Responder::new();
1515 me.handle_mlme_request(wlan_sme::MlmeRequest::GetIfaceHistogramStats(responder))
1516 .await
1517 .expect("Failed to send MlmeRequest::GetIfaceHistogramStats");
1518 assert_eq!(
1519 receiver.await,
1520 Ok(fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(
1521 zx::sys::ZX_ERR_NOT_SUPPORTED
1522 ))
1523 );
1524 }
1525
1526 #[test]
1527 fn drop_mgmt_frame_wrong_bssid() {
1528 let frame = [
1529 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0x10, 0, ];
1537 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1538 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1539 }
1540
1541 #[test]
1542 fn drop_mgmt_frame_wrong_dst_addr() {
1543 let frame = [
1544 0b11010000, 0b00000000, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1552 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1553 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1554 }
1555
1556 #[test]
1557 fn mgmt_frame_ok_broadcast() {
1558 let frame = [
1559 0b11010000, 0b00000000, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1567 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1568 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1569 }
1570
1571 #[test]
1572 fn mgmt_frame_ok_client_addr() {
1573 let frame = [
1574 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1582 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1583 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1584 }
1585
1586 #[test]
1587 fn drop_data_frame_wrong_bssid() {
1588 let frame = [
1589 0b01001000,
1591 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1598 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1599 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1600 }
1601
1602 #[test]
1603 fn drop_data_frame_wrong_dst_addr() {
1604 let frame = [
1605 0b01001000,
1607 0b00000010, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1614 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1615 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1616 }
1617
1618 #[test]
1619 fn data_frame_ok_broadcast() {
1620 let frame = [
1621 0b01001000,
1623 0b00000010, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1630 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1631 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1632 }
1633
1634 #[test]
1635 fn data_frame_ok_client_addr() {
1636 let frame = [
1637 0b01001000,
1639 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1646 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1647 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1648 }
1649}