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.primary == rx_info.channel.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.channel
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::WlanChannel,
346 ) -> Result<(), zx::Status> {
347 self.channel_state.bind(&mut self.ctx, &mut self.scanner).set_main_channel(channel).await
348 }
349
350 async fn on_sme_scan(&mut self, req: fidl_mlme::ScanRequest) {
351 let txn_id = req.txn_id;
352 let _ = self.scanner.bind(&mut self.ctx).on_sme_scan(req).await.map_err(|e| {
353 error!("Scan failed in MLME: {:?}", e);
354 let code = match e {
355 Error::ScanError(scan_error) => scan_error.into(),
356 _ => fidl_mlme::ScanResultCode::InternalError,
357 };
358 self.ctx
359 .device
360 .send_mlme_event(fidl_mlme::MlmeEvent::OnScanEnd {
361 end: fidl_mlme::ScanEnd { txn_id, code },
362 })
363 .unwrap_or_else(|e| error!("error sending MLME ScanEnd: {}", e));
364 });
365 }
366
367 async fn on_sme_connect(&mut self, req: fidl_mlme::ConnectRequest) -> Result<(), Error> {
368 if let Err(e) = self.scanner.bind(&mut self.ctx).cancel_ongoing_scan().await {
371 warn!("Failed to cancel ongoing scan before connect: {}.", e);
372 }
373
374 let bssid = req.selected_bss.bssid;
375 let result = match req.selected_bss.try_into() {
376 Ok(bss) => {
377 let req = ParsedConnectRequest {
378 selected_bss: bss,
379 connect_failure_timeout: req.connect_failure_timeout,
380 auth_type: req.auth_type,
381 security_ie: req.security_ie,
382 };
383 self.join_device(&req.selected_bss).await.map(|cap| (req, cap))
384 }
385 Err(e) => Err(Error::Status(
386 format!("Error parsing BssDescription: {:?}", e),
387 zx::Status::IO_INVALID,
388 )),
389 };
390
391 match result {
392 Ok((req, client_capabilities)) => {
393 self.sta.replace(Client::new(
394 req,
395 device::try_query_iface_mac(&mut self.ctx.device).await?,
396 client_capabilities,
397 ));
398 if let Some(sta) = &mut self.sta {
399 sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
400 .start_connecting()
401 .await;
402 }
403 Ok(())
404 }
405 Err(e) => {
406 error!("Error setting up device for join: {}", e);
407 self.ctx.device.send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf {
410 resp: fidl_mlme::ConnectConfirm {
411 peer_sta_address: bssid,
412 result_code: fidl_ieee80211::StatusCode::JoinFailure,
413 association_id: 0,
414 association_ies: vec![],
415 },
416 })?;
417 Err(e)
418 }
419 }
420 }
421
422 async fn join_device(&mut self, bss: &BssDescription) -> Result<ClientCapabilities, Error> {
423 let info = ddk_converter::mlme_device_info_from_softmac(
424 device::try_query(&mut self.ctx.device).await?,
425 )?;
426 let join_caps = derive_join_capabilities(Channel::from(bss.channel), bss.rates(), &info)
427 .map_err(|e| {
428 Error::Status(
429 format!("Failed to derive join capabilities: {:?}", e),
430 zx::Status::NOT_SUPPORTED,
431 )
432 })?;
433
434 self.set_main_channel(bss.channel.into())
435 .await
436 .map_err(|status| Error::Status(format!("Error setting device channel"), status))?;
437
438 let join_bss_request = fidl_driver_common::JoinBssRequest {
439 bssid: Some(bss.bssid.to_array()),
440 bss_type: Some(fidl_ieee80211::BssType::Infrastructure),
441 remote: Some(true),
442 beacon_period: Some(bss.beacon_period),
443 ..Default::default()
444 };
445
446 self.ctx
448 .device
449 .join_bss(&join_bss_request)
450 .await
451 .map(|()| join_caps)
452 .map_err(|status| Error::Status(format!("Error setting BSS in driver"), status))
453 }
454
455 async fn on_sme_query_device_info(
456 &mut self,
457 responder: wlan_sme::responder::Responder<fidl_mlme::DeviceInfo>,
458 ) -> Result<(), Error> {
459 let info = ddk_converter::mlme_device_info_from_softmac(
460 device::try_query(&mut self.ctx.device).await?,
461 )?;
462 responder.respond(info);
463 Ok(())
464 }
465
466 async fn on_sme_query_mac_sublayer_support(
467 &mut self,
468 responder: wlan_sme::responder::Responder<fidl_common::MacSublayerSupport>,
469 ) -> Result<(), Error> {
470 let support = device::try_query_mac_sublayer_support(&mut self.ctx.device).await?;
471 responder.respond(support);
472 Ok(())
473 }
474
475 async fn on_sme_query_security_support(
476 &mut self,
477 responder: wlan_sme::responder::Responder<fidl_common::SecuritySupport>,
478 ) -> Result<(), Error> {
479 let support = device::try_query_security_support(&mut self.ctx.device).await?;
480 responder.respond(support);
481 Ok(())
482 }
483
484 async fn on_sme_query_spectrum_management_support(
485 &mut self,
486 responder: wlan_sme::responder::Responder<fidl_common::SpectrumManagementSupport>,
487 ) -> Result<(), Error> {
488 let support = device::try_query_spectrum_management_support(&mut self.ctx.device).await?;
489 responder.respond(support);
490 Ok(())
491 }
492}
493
494pub struct ParsedAssociateResp {
495 pub association_id: u16,
496 pub capabilities: CapabilityInfo,
497 pub rates: Vec<ie::SupportedRate>,
498 pub ht_cap: Option<ie::HtCapabilities>,
499 pub vht_cap: Option<ie::VhtCapabilities>,
500}
501
502impl ParsedAssociateResp {
503 pub fn parse<B: SplitByteSlice>(assoc_resp_frame: &mac::AssocRespFrame<B>) -> Self {
504 let mut parsed = ParsedAssociateResp {
505 association_id: assoc_resp_frame.assoc_resp_hdr.aid,
506 capabilities: assoc_resp_frame.assoc_resp_hdr.capabilities,
507 rates: vec![],
508 ht_cap: None,
509 vht_cap: None,
510 };
511 for (id, body) in assoc_resp_frame.ies() {
512 match id {
513 Id::SUPPORTED_RATES => match ie::parse_supported_rates(body) {
514 Err(e) => warn!("invalid Supported Rates: {}", e),
515 Ok(supported_rates) => {
516 parsed.rates.extend(supported_rates.iter());
518 }
519 },
520 Id::EXTENDED_SUPPORTED_RATES => match ie::parse_extended_supported_rates(body) {
521 Err(e) => warn!("invalid Extended Supported Rates: {}", e),
522 Ok(supported_rates) => {
523 parsed.rates.extend(supported_rates.iter());
525 }
526 },
527 Id::HT_CAPABILITIES => match ie::parse_ht_capabilities(body) {
528 Err(e) => warn!("invalid HT Capabilities: {}", e),
529 Ok(ht_cap) => {
530 parsed.ht_cap = Some(*ht_cap);
531 }
532 },
533 Id::VHT_CAPABILITIES => match ie::parse_vht_capabilities(body) {
534 Err(e) => warn!("invalid VHT Capabilities: {}", e),
535 Ok(vht_cap) => {
536 parsed.vht_cap = Some(*vht_cap);
537 }
538 },
539 _ => {}
541 }
542 }
543 parsed
544 }
545}
546
547#[cfg(test)]
548mod tests {
549 use super::state::DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT;
550 use super::*;
551 use crate::MlmeImpl;
552 use crate::client::test_utils::*;
553 use crate::device::{FakeDevice, LinkStatus, test_utils};
554 use crate::test_utils::MockWlanRxInfo;
555 use assert_matches::assert_matches;
556 use fidl_fuchsia_wlan_common as fidl_common;
557 use fidl_fuchsia_wlan_internal as fidl_internal;
558 use fidl_fuchsia_wlan_mlme as fidl_mlme;
559 use ieee80211::Ssid;
560 use wlan_common::channel::Cbw;
561 use wlan_common::fake_fidl_bss_description;
562 use wlan_sme::responder::Responder;
563
564 #[fuchsia::test(allow_stalls = false)]
565 async fn spawns_new_sta_on_connect_request_from_sme() {
566 let mut m = MockObjects::new().await;
567 let mut me = m.make_mlme().await;
568 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
569 me.on_sme_connect(fidl_mlme::ConnectRequest {
570 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
571 connect_failure_timeout: 100,
572 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
573 sae_password: vec![],
574 wep_key: None,
575 security_ie: vec![],
576 owe_public_key: None,
577 })
578 .await
579 .expect("valid ConnectRequest should be handled successfully");
580 me.get_bound_client().expect("client sta should have been created by now.");
581 }
582
583 #[fuchsia::test(allow_stalls = false)]
584 async fn fails_to_connect_if_channel_unknown() {
585 let mut m = MockObjects::new().await;
586 let mut me = m.make_mlme().await;
587 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
588 let mut req = fidl_mlme::ConnectRequest {
589 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
590 connect_failure_timeout: 100,
591 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
592 sae_password: vec![],
593 wep_key: None,
594 security_ie: vec![],
595 owe_public_key: None,
596 };
597
598 req.selected_bss.channel.cbw = fidl_fuchsia_wlan_ieee80211::ChannelBandwidth::unknown();
599 me.on_sme_connect(req)
600 .await
601 .expect_err("ConnectRequest with unknown channel should be rejected");
602 assert!(me.get_bound_client().is_none());
603 }
604
605 async fn handle_association_status_checks_and_signal_reports(
615 mock_objects: &mut MockObjects,
616 mlme: &mut ClientMlme<FakeDevice>,
617 beacon_count: u32,
618 ) {
619 for _ in 0..beacon_count / super::state::ASSOCIATION_STATUS_TIMEOUT_BEACON_COUNT {
620 let (_, timed_event, _) = mock_objects
621 .time_stream
622 .try_next()
623 .unwrap()
624 .expect("Should have scheduled a timed event");
625 mlme.handle_timeout(timed_event.event).await;
626 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 0);
627 mock_objects
628 .fake_device_state
629 .lock()
630 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
631 .expect("error reading SignalReport.indication");
632 }
633 }
634
635 #[fuchsia::test(allow_stalls = false)]
636 async fn test_auto_deauth_uninterrupted_interval() {
637 let mut mock_objects = MockObjects::new().await;
638 let mut mlme = mock_objects.make_mlme().await;
639 mlme.make_client_station();
640 let mut client = mlme.get_bound_client().expect("client should be present");
641
642 client.move_to_associated_state();
643
644 handle_association_status_checks_and_signal_reports(
646 &mut mock_objects,
647 &mut mlme,
648 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
649 )
650 .await;
651
652 let (_, timed_event, _) = mock_objects
654 .time_stream
655 .try_next()
656 .unwrap()
657 .expect("Should have scheduled a timed event");
658
659 mlme.handle_timeout(timed_event.event).await;
661 mock_objects
662 .fake_device_state
663 .lock()
664 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
665 .expect("error reading SignalReport.indication");
666 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
667 #[rustfmt::skip]
668 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
669 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, ][..]);
678 let deauth_ind = mock_objects
679 .fake_device_state
680 .lock()
681 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
682 .expect("error reading DEAUTHENTICATE.indication");
683 assert_eq!(
684 deauth_ind,
685 fidl_mlme::DeauthenticateIndication {
686 peer_sta_address: BSSID.to_array(),
687 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
688 locally_initiated: true,
689 }
690 );
691 }
692
693 #[fuchsia::test(allow_stalls = false)]
694 async fn test_auto_deauth_received_beacon() {
695 let mut mock_objects = MockObjects::new().await;
696 let mut mlme = mock_objects.make_mlme().await;
697 mlme.make_client_station();
698 let mut client = mlme.get_bound_client().expect("client should be present");
699
700 client.move_to_associated_state();
701
702 handle_association_status_checks_and_signal_reports(
704 &mut mock_objects,
705 &mut mlme,
706 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
707 )
708 .await;
709
710 mlme.handle_mac_frame_rx(
713 BEACON_FRAME,
714 fidl_softmac::WlanRxInfo {
715 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
716 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
717 phy: fidl_ieee80211::WlanPhyType::Dsss,
718 data_rate: 0,
719 channel: mlme.channel_state.get_main_channel().unwrap(),
720 mcs: 0,
721 rssi_dbm: 0,
722 snr_dbh: 0,
723 },
724 0.into(),
725 )
726 .await;
727
728 handle_association_status_checks_and_signal_reports(
730 &mut mock_objects,
731 &mut mlme,
732 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
733 )
734 .await;
735
736 let (_, timed_event2, _) = mock_objects
738 .time_stream
739 .try_next()
740 .unwrap()
741 .expect("Should have scheduled a timed event");
742
743 mlme.handle_timeout(timed_event2.event).await;
745 mock_objects
746 .fake_device_state
747 .lock()
748 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
749 .expect("error reading SignalReport.indication");
750 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
751 #[rustfmt::skip]
752 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
753 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, ][..]);
762 let deauth_ind = mock_objects
763 .fake_device_state
764 .lock()
765 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
766 .expect("error reading DEAUTHENTICATE.indication");
767 assert_eq!(
768 deauth_ind,
769 fidl_mlme::DeauthenticateIndication {
770 peer_sta_address: BSSID.to_array(),
771 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
772 locally_initiated: true,
773 }
774 );
775 }
776
777 #[fuchsia::test(allow_stalls = false)]
778 async fn client_send_scan_end_on_mlme_scan_busy() {
779 let mut m = MockObjects::new().await;
780 let mut me = m.make_mlme().await;
781 me.make_client_station();
782
783 me.on_sme_scan(scan_req()).await;
785 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
786
787 let scan_end = m
788 .fake_device_state
789 .lock()
790 .next_mlme_msg::<fidl_mlme::ScanEnd>()
791 .expect("error reading MLME ScanEnd");
792 assert_eq!(
793 scan_end,
794 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
795 );
796 }
797
798 #[fuchsia::test(allow_stalls = false)]
799 async fn client_send_scan_end_on_scan_busy() {
800 let mut m = MockObjects::new().await;
801 let mut me = m.make_mlme().await;
802 me.make_client_station();
803
804 me.on_sme_scan(scan_req()).await;
806 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
807
808 let scan_end = m
809 .fake_device_state
810 .lock()
811 .next_mlme_msg::<fidl_mlme::ScanEnd>()
812 .expect("error reading MLME ScanEnd");
813 assert_eq!(
814 scan_end,
815 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
816 );
817 }
818
819 #[fuchsia::test(allow_stalls = false)]
820 async fn client_send_scan_end_on_mlme_scan_invalid_args() {
821 let mut m = MockObjects::new().await;
822 let mut me = m.make_mlme().await;
823
824 me.make_client_station();
825 me.on_sme_scan(fidl_mlme::ScanRequest {
826 txn_id: 1337,
827 scan_type: fidl_mlme::ScanTypes::Passive,
828 channel_list: vec![], ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
830 probe_delay: 0,
831 min_channel_time: 100,
832 max_channel_time: 300,
833 })
834 .await;
835 let scan_end = m
836 .fake_device_state
837 .lock()
838 .next_mlme_msg::<fidl_mlme::ScanEnd>()
839 .expect("error reading MLME ScanEnd");
840 assert_eq!(
841 scan_end,
842 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
843 );
844 }
845
846 #[fuchsia::test(allow_stalls = false)]
847 async fn client_send_scan_end_on_scan_invalid_args() {
848 let mut m = MockObjects::new().await;
849 let mut me = m.make_mlme().await;
850
851 me.make_client_station();
852 me.on_sme_scan(fidl_mlme::ScanRequest {
853 txn_id: 1337,
854 scan_type: fidl_mlme::ScanTypes::Passive,
855 channel_list: vec![6],
856 ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
857 probe_delay: 0,
858 min_channel_time: 300, max_channel_time: 100,
860 })
861 .await;
862 let scan_end = m
863 .fake_device_state
864 .lock()
865 .next_mlme_msg::<fidl_mlme::ScanEnd>()
866 .expect("error reading MLME ScanEnd");
867 assert_eq!(
868 scan_end,
869 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
870 );
871 }
872
873 #[fuchsia::test(allow_stalls = false)]
874 async fn client_send_scan_end_on_passive_scan_fails() {
875 let mut m = MockObjects::new().await;
876 m.fake_device_state.lock().config.start_passive_scan_fails = true;
877 let mut me = m.make_mlme().await;
878
879 me.make_client_station();
880 me.on_sme_scan(scan_req()).await;
881 let scan_end = m
882 .fake_device_state
883 .lock()
884 .next_mlme_msg::<fidl_mlme::ScanEnd>()
885 .expect("error reading MLME ScanEnd");
886 assert_eq!(
887 scan_end,
888 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::NotSupported }
889 );
890 }
891
892 #[fuchsia::test(allow_stalls = false)]
893 async fn mlme_respond_to_query_device_info() {
894 let mut mock_objects = MockObjects::new().await;
895 let mut mlme = mock_objects.make_mlme().await;
896
897 let (responder, receiver) = Responder::new();
898 mlme.handle_mlme_request(wlan_sme::MlmeRequest::QueryDeviceInfo(responder))
899 .await
900 .expect("Failed to send MlmeRequest::Connect");
901 assert_eq!(
902 receiver.await.unwrap(),
903 fidl_mlme::DeviceInfo {
904 sta_addr: IFACE_MAC.to_array(),
905 factory_addr: IFACE_MAC.to_array(),
906 role: fidl_common::WlanMacRole::Client,
907 bands: test_utils::fake_mlme_band_caps(),
908 softmac_hardware_capability: 0,
909 qos_capable: false,
910 }
911 );
912 }
913
914 #[fuchsia::test(allow_stalls = false)]
915 async fn mlme_respond_to_query_mac_sublayer_support() {
916 let mut m = MockObjects::new().await;
917 let mut me = m.make_mlme().await;
918
919 let (responder, receiver) = Responder::new();
920 me.handle_mlme_request(wlan_sme::MlmeRequest::QueryMacSublayerSupport(responder))
921 .await
922 .expect("Failed to send MlmeRequest::Connect");
923 let resp = receiver.await.unwrap();
924 assert_eq!(resp.rate_selection_offload.unwrap().supported, Some(false));
925 assert_eq!(
926 resp.data_plane.unwrap().data_plane_type,
927 Some(fidl_common::DataPlaneType::EthernetDevice)
928 );
929 assert_eq!(resp.device.as_ref().unwrap().is_synthetic, Some(true));
930 assert_eq!(
931 resp.device.as_ref().unwrap().mac_implementation_type,
932 Some(fidl_common::MacImplementationType::Softmac)
933 );
934 assert_eq!(resp.device.unwrap().tx_status_report_supported, Some(true));
935 }
936
937 #[fuchsia::test(allow_stalls = false)]
938 async fn mlme_respond_to_query_security_support() {
939 let mut m = MockObjects::new().await;
940 let mut me = m.make_mlme().await;
941
942 let (responder, receiver) = Responder::new();
943 assert_matches!(
944 me.handle_mlme_request(wlan_sme::MlmeRequest::QuerySecuritySupport(responder)).await,
945 Ok(())
946 );
947 let resp = receiver.await.unwrap();
948 assert_eq!(resp.mfp.unwrap().supported, Some(false));
949 assert_eq!(resp.sae.as_ref().unwrap().driver_handler_supported, Some(false));
950 assert_eq!(resp.sae.unwrap().sme_handler_supported, Some(false));
951 }
952
953 #[fuchsia::test(allow_stalls = false)]
954 async fn mlme_respond_to_query_spectrum_management_support() {
955 let mut m = MockObjects::new().await;
956 let mut me = m.make_mlme().await;
957
958 let (responder, receiver) = Responder::new();
959 me.handle_mlme_request(wlan_sme::MlmeRequest::QuerySpectrumManagementSupport(responder))
960 .await
961 .expect("Failed to send MlmeRequest::QuerySpectrumManagementSupport");
962 assert_eq!(receiver.await.unwrap().dfs.unwrap().supported, Some(true));
963 }
964
965 #[fuchsia::test(allow_stalls = false)]
966 async fn mlme_connect_unprotected_happy_path() {
967 let mut m = MockObjects::new().await;
968 let mut me = m.make_mlme().await;
969 let channel = Channel::new(6, Cbw::Cbw40);
970 let connect_req = fidl_mlme::ConnectRequest {
971 selected_bss: fake_fidl_bss_description!(Open,
972 ssid: Ssid::try_from("ssid").unwrap().into(),
973 bssid: BSSID.to_array(),
974 channel: channel.clone(),
975 ),
976 connect_failure_timeout: 100,
977 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
978 sae_password: vec![],
979 wep_key: None,
980 security_ie: vec![],
981 owe_public_key: None,
982 };
983 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
984 .await
985 .expect("Failed to send MlmeRequest::Connect");
986
987 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
989 assert_eq!(ids.len(), 1);
990 });
991
992 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
994 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
995 #[rustfmt::skip]
996 let expected = vec![
997 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, ];
1009 assert_eq!(&frame[..], &expected[..]);
1010
1011 #[rustfmt::skip]
1013 let auth_resp_success = vec![
1014 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, ];
1026 me.handle_mac_frame_rx(
1027 &auth_resp_success[..],
1028 MockWlanRxInfo::with_channel(channel.into()).into(),
1029 0.into(),
1030 )
1031 .await;
1032
1033 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1035 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1036 #[rustfmt::skip]
1037 let expected = vec![
1038 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, ];
1060 assert_eq!(&frame[..], &expected[..]);
1061
1062 #[rustfmt::skip]
1064 let assoc_resp_success = vec![
1065 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,
1079 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1083 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ];
1087 me.handle_mac_frame_rx(
1088 &assoc_resp_success[..],
1089 MockWlanRxInfo::with_channel(channel.into()).into(),
1090 0.into(),
1091 )
1092 .await;
1093
1094 let msg = m
1096 .fake_device_state
1097 .lock()
1098 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1099 .expect("expect ConnectConf");
1100 assert_eq!(
1101 msg,
1102 fidl_mlme::ConnectConfirm {
1103 peer_sta_address: BSSID.to_array(),
1104 result_code: fidl_ieee80211::StatusCode::Success,
1105 association_id: 42,
1106 association_ies: vec![
1107 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
1110 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1114 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
1118 }
1119 );
1120
1121 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
1123 }
1124
1125 #[fuchsia::test(allow_stalls = false)]
1126 async fn mlme_connect_protected_happy_path() {
1127 let mut m = MockObjects::new().await;
1128 let mut me = m.make_mlme().await;
1129 let channel = Channel::new(6, Cbw::Cbw40);
1130 let connect_req = fidl_mlme::ConnectRequest {
1131 selected_bss: fake_fidl_bss_description!(Wpa2,
1132 ssid: Ssid::try_from("ssid").unwrap().into(),
1133 bssid: BSSID.to_array(),
1134 channel: channel.clone(),
1135 ),
1136 connect_failure_timeout: 100,
1137 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1138 sae_password: vec![],
1139 wep_key: None,
1140 security_ie: vec![
1141 48, 18, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 2, ],
1147 owe_public_key: None,
1148 };
1149 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1150 .await
1151 .expect("Failed to send MlmeRequest::Connect");
1152
1153 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
1155 assert_eq!(ids.len(), 1);
1156 });
1157
1158 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1160 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1161 #[rustfmt::skip]
1162 let expected = vec![
1163 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, ];
1175 assert_eq!(&frame[..], &expected[..]);
1176
1177 #[rustfmt::skip]
1179 let auth_resp_success = vec![
1180 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, ];
1192 me.handle_mac_frame_rx(
1193 &auth_resp_success[..],
1194 MockWlanRxInfo::with_channel(channel.into()).into(),
1195 0.into(),
1196 )
1197 .await;
1198
1199 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1201 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1202 #[rustfmt::skip]
1203 let expected = vec![
1204 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, ];
1231 assert_eq!(&frame[..], &expected[..]);
1232
1233 #[rustfmt::skip]
1235 let assoc_resp_success = vec![
1236 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,
1250 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, ];
1263 me.handle_mac_frame_rx(
1264 &assoc_resp_success[..],
1265 MockWlanRxInfo::with_channel(channel.into()).into(),
1266 0.into(),
1267 )
1268 .await;
1269
1270 let msg = m
1272 .fake_device_state
1273 .lock()
1274 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1275 .expect("expect ConnectConf");
1276 assert_eq!(
1277 msg,
1278 fidl_mlme::ConnectConfirm {
1279 peer_sta_address: BSSID.to_array(),
1280 result_code: fidl_ieee80211::StatusCode::Success,
1281 association_id: 42,
1282 association_ies: vec![
1283 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,
1294 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
1299 }
1300 );
1301
1302 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::DOWN);
1304
1305 me.handle_mlme_request(wlan_sme::MlmeRequest::SetCtrlPort(
1307 fidl_mlme::SetControlledPortRequest {
1308 peer_sta_address: BSSID.to_array(),
1309 state: fidl_mlme::ControlledPortState::Open,
1310 },
1311 ))
1312 .await
1313 .expect("expect sending msg to succeed");
1314
1315 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
1317 }
1318
1319 #[fuchsia::test(allow_stalls = false)]
1320 async fn mlme_connect_vht() {
1321 let mut m = MockObjects::new().await;
1322 let mut me = m.make_mlme().await;
1323 let channel = Channel::new(36, Cbw::Cbw40);
1324 let connect_req = fidl_mlme::ConnectRequest {
1325 selected_bss: fake_fidl_bss_description!(Open,
1326 ssid: Ssid::try_from("ssid").unwrap().into(),
1327 bssid: BSSID.to_array(),
1328 channel: channel.clone(),
1329 ),
1330 connect_failure_timeout: 100,
1331 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1332 sae_password: vec![],
1333 wep_key: None,
1334 security_ie: vec![],
1335 owe_public_key: None,
1336 };
1337 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1338 .await
1339 .expect("Failed to send MlmeRequest::Connect.");
1340
1341 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
1343 assert_eq!(ids.len(), 1);
1344 });
1345
1346 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1348 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1349
1350 #[rustfmt::skip]
1352 let auth_resp_success = vec![
1353 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, ];
1365 me.handle_mac_frame_rx(
1366 &auth_resp_success[..],
1367 MockWlanRxInfo::with_channel(channel.into()).into(),
1368 0.into(),
1369 )
1370 .await;
1371
1372 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1374 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1375 #[rustfmt::skip]
1376 let expected = vec![
1377 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, ];
1399 assert_eq!(&frame[..], &expected[..]);
1400 }
1401
1402 #[fuchsia::test(allow_stalls = false)]
1403 async fn mlme_connect_timeout() {
1404 let mut m = MockObjects::new().await;
1405 let mut me = m.make_mlme().await;
1406 let connect_req = fidl_mlme::ConnectRequest {
1407 selected_bss: fake_fidl_bss_description!(Open, bssid: BSSID.to_array()),
1408 connect_failure_timeout: 100,
1409 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1410 sae_password: vec![],
1411 wep_key: None,
1412 security_ie: vec![],
1413 owe_public_key: None,
1414 };
1415 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1416 .await
1417 .expect("Failed to send MlmeRequest::Connect.");
1418
1419 let (event, _id) = assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(events) => {
1421 assert_eq!(events.len(), 1);
1422 events[0].clone()
1423 });
1424
1425 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1427 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1428
1429 me.handle_timeout(event).await;
1431
1432 let msg = m
1434 .fake_device_state
1435 .lock()
1436 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1437 .expect("expect msg");
1438 assert_eq!(
1439 msg,
1440 fidl_mlme::ConnectConfirm {
1441 peer_sta_address: BSSID.to_array(),
1442 result_code: fidl_ieee80211::StatusCode::RejectedSequenceTimeout,
1443 association_id: 0,
1444 association_ies: vec![],
1445 },
1446 );
1447 }
1448
1449 #[fuchsia::test(allow_stalls = false)]
1450 async fn mlme_reconnect_no_sta() {
1451 let mut m = MockObjects::new().await;
1452 let mut me = m.make_mlme().await;
1453
1454 let reconnect_req = fidl_mlme::ReconnectRequest { peer_sta_address: [1, 2, 3, 4, 5, 6] };
1455 let result = me.handle_mlme_request(wlan_sme::MlmeRequest::Reconnect(reconnect_req)).await;
1456 let err = result.unwrap_err();
1457 let mlme_err = err.downcast_ref::<Error>().expect("expected Mlme Error");
1458 assert_matches!(mlme_err, Error::Status(_, zx::Status::BAD_STATE));
1459
1460 let msg = m
1462 .fake_device_state
1463 .lock()
1464 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1465 .expect("expect msg");
1466 assert_eq!(
1467 msg,
1468 fidl_mlme::ConnectConfirm {
1469 peer_sta_address: [1, 2, 3, 4, 5, 6],
1470 result_code: fidl_ieee80211::StatusCode::DeniedNoAssociationExists,
1471 association_id: 0,
1472 association_ies: vec![],
1473 },
1474 );
1475 }
1476
1477 #[fuchsia::test(allow_stalls = false)]
1478 async fn mlme_respond_to_get_iface_stats_with_error_status() {
1479 let mut m = MockObjects::new().await;
1480 let mut me = m.make_mlme().await;
1481
1482 let (responder, receiver) = Responder::new();
1483 me.handle_mlme_request(wlan_sme::MlmeRequest::GetIfaceStats(responder))
1484 .await
1485 .expect("Failed to send MlmeRequest::GetIfaceStats.");
1486 assert_eq!(
1487 receiver.await,
1488 Ok(fidl_mlme::GetIfaceStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED))
1489 );
1490 }
1491
1492 #[fuchsia::test(allow_stalls = false)]
1493 async fn mlme_respond_to_get_iface_histogram_stats_with_error_status() {
1494 let mut m = MockObjects::new().await;
1495 let mut me = m.make_mlme().await;
1496
1497 let (responder, receiver) = Responder::new();
1498 me.handle_mlme_request(wlan_sme::MlmeRequest::GetIfaceHistogramStats(responder))
1499 .await
1500 .expect("Failed to send MlmeRequest::GetIfaceHistogramStats");
1501 assert_eq!(
1502 receiver.await,
1503 Ok(fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(
1504 zx::sys::ZX_ERR_NOT_SUPPORTED
1505 ))
1506 );
1507 }
1508
1509 #[test]
1510 fn drop_mgmt_frame_wrong_bssid() {
1511 let frame = [
1512 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0x10, 0, ];
1520 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1521 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1522 }
1523
1524 #[test]
1525 fn drop_mgmt_frame_wrong_dst_addr() {
1526 let frame = [
1527 0b11010000, 0b00000000, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1535 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1536 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1537 }
1538
1539 #[test]
1540 fn mgmt_frame_ok_broadcast() {
1541 let frame = [
1542 0b11010000, 0b00000000, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1550 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1551 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1552 }
1553
1554 #[test]
1555 fn mgmt_frame_ok_client_addr() {
1556 let frame = [
1557 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1565 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1566 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1567 }
1568
1569 #[test]
1570 fn drop_data_frame_wrong_bssid() {
1571 let frame = [
1572 0b01001000,
1574 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1581 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1582 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1583 }
1584
1585 #[test]
1586 fn drop_data_frame_wrong_dst_addr() {
1587 let frame = [
1588 0b01001000,
1590 0b00000010, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1597 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1598 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1599 }
1600
1601 #[test]
1602 fn data_frame_ok_broadcast() {
1603 let frame = [
1604 0b01001000,
1606 0b00000010, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1613 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1614 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1615 }
1616
1617 #[test]
1618 fn data_frame_ok_client_addr() {
1619 let frame = [
1620 0b01001000,
1622 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1629 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1630 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1631 }
1632}