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_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
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::Bandwidth;
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, _) =
629 mock_objects.time_stream.try_recv().expect("Should have scheduled a timed event");
630 mlme.handle_timeout(timed_event.event).await;
631 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 0);
632 mock_objects
633 .fake_device_state
634 .lock()
635 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
636 .expect("error reading SignalReport.indication");
637 }
638 }
639
640 #[fuchsia::test(allow_stalls = false)]
641 async fn test_auto_deauth_uninterrupted_interval() {
642 let mut mock_objects = MockObjects::new().await;
643 let mut mlme = mock_objects.make_mlme().await;
644 mlme.make_client_station();
645 let mut client = mlme.get_bound_client().expect("client should be present");
646
647 client.move_to_associated_state();
648
649 handle_association_status_checks_and_signal_reports(
651 &mut mock_objects,
652 &mut mlme,
653 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
654 )
655 .await;
656
657 let (_, timed_event, _) =
659 mock_objects.time_stream.try_recv().expect("Should have scheduled a timed event");
660
661 mlme.handle_timeout(timed_event.event).await;
663 mock_objects
664 .fake_device_state
665 .lock()
666 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
667 .expect("error reading SignalReport.indication");
668 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
669 #[rustfmt::skip]
670 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
671 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, ][..]);
680 let deauth_ind = mock_objects
681 .fake_device_state
682 .lock()
683 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
684 .expect("error reading DEAUTHENTICATE.indication");
685 assert_eq!(
686 deauth_ind,
687 fidl_mlme::DeauthenticateIndication {
688 peer_sta_address: BSSID.to_array(),
689 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
690 locally_initiated: true,
691 }
692 );
693 }
694
695 #[fuchsia::test(allow_stalls = false)]
696 async fn test_auto_deauth_received_beacon() {
697 let mut mock_objects = MockObjects::new().await;
698 let mut mlme = mock_objects.make_mlme().await;
699 mlme.make_client_station();
700 let mut client = mlme.get_bound_client().expect("client should be present");
701
702 client.move_to_associated_state();
703
704 handle_association_status_checks_and_signal_reports(
706 &mut mock_objects,
707 &mut mlme,
708 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
709 )
710 .await;
711
712 let main_channel = mlme.channel_state.get_primary().unwrap();
715 mlme.handle_mac_frame_rx(
716 BEACON_FRAME,
717 fidl_softmac::WlanRxInfo {
718 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
719 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
720 phy: fidl_ieee80211::WlanPhyType::Dsss,
721 data_rate: 0,
722 primary: main_channel,
723 mcs: 0,
724 rssi_dbm: 0,
725 snr_dbh: 0,
726 bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
727 vht_secondary_80_channel: fidl_ieee80211::ChannelNumber {
728 band: main_channel.band,
729 number: 0,
730 },
731 },
732 0.into(),
733 )
734 .await;
735
736 handle_association_status_checks_and_signal_reports(
738 &mut mock_objects,
739 &mut mlme,
740 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
741 )
742 .await;
743
744 let (_, timed_event2, _) =
746 mock_objects.time_stream.try_recv().expect("Should have scheduled a timed event");
747
748 mlme.handle_timeout(timed_event2.event).await;
750 mock_objects
751 .fake_device_state
752 .lock()
753 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
754 .expect("error reading SignalReport.indication");
755 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
756 #[rustfmt::skip]
757 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
758 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, ][..]);
767 let deauth_ind = mock_objects
768 .fake_device_state
769 .lock()
770 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
771 .expect("error reading DEAUTHENTICATE.indication");
772 assert_eq!(
773 deauth_ind,
774 fidl_mlme::DeauthenticateIndication {
775 peer_sta_address: BSSID.to_array(),
776 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
777 locally_initiated: true,
778 }
779 );
780 }
781
782 #[fuchsia::test(allow_stalls = false)]
783 async fn client_send_scan_end_on_mlme_scan_busy() {
784 let mut m = MockObjects::new().await;
785 let mut me = m.make_mlme().await;
786 me.make_client_station();
787
788 me.on_sme_scan(scan_req()).await;
790 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
791
792 let scan_end = m
793 .fake_device_state
794 .lock()
795 .next_mlme_msg::<fidl_mlme::ScanEnd>()
796 .expect("error reading MLME ScanEnd");
797 assert_eq!(
798 scan_end,
799 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
800 );
801 }
802
803 #[fuchsia::test(allow_stalls = false)]
804 async fn client_send_scan_end_on_scan_busy() {
805 let mut m = MockObjects::new().await;
806 let mut me = m.make_mlme().await;
807 me.make_client_station();
808
809 me.on_sme_scan(scan_req()).await;
811 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
812
813 let scan_end = m
814 .fake_device_state
815 .lock()
816 .next_mlme_msg::<fidl_mlme::ScanEnd>()
817 .expect("error reading MLME ScanEnd");
818 assert_eq!(
819 scan_end,
820 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
821 );
822 }
823
824 #[fuchsia::test(allow_stalls = false)]
825 async fn client_send_scan_end_on_mlme_scan_invalid_args() {
826 let mut m = MockObjects::new().await;
827 let mut me = m.make_mlme().await;
828
829 me.make_client_station();
830 me.on_sme_scan(fidl_mlme::ScanRequest {
831 txn_id: 1337,
832 scan_type: fidl_mlme::ScanTypes::Passive,
833 channel_list: vec![], ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
835 probe_delay: 0,
836 min_channel_time: 100,
837 max_channel_time: 300,
838 })
839 .await;
840 let scan_end = m
841 .fake_device_state
842 .lock()
843 .next_mlme_msg::<fidl_mlme::ScanEnd>()
844 .expect("error reading MLME ScanEnd");
845 assert_eq!(
846 scan_end,
847 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
848 );
849 }
850
851 #[fuchsia::test(allow_stalls = false)]
852 async fn client_send_scan_end_on_scan_invalid_args() {
853 let mut m = MockObjects::new().await;
854 let mut me = m.make_mlme().await;
855
856 me.make_client_station();
857 me.on_sme_scan(fidl_mlme::ScanRequest {
858 txn_id: 1337,
859 scan_type: fidl_mlme::ScanTypes::Passive,
860 channel_list: vec![fidl_ieee80211::ChannelNumber {
861 band: fidl_ieee80211::WlanBand::TwoGhz,
862 number: 6,
863 }],
864 ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
865 probe_delay: 0,
866 min_channel_time: 300, max_channel_time: 100,
868 })
869 .await;
870 let scan_end = m
871 .fake_device_state
872 .lock()
873 .next_mlme_msg::<fidl_mlme::ScanEnd>()
874 .expect("error reading MLME ScanEnd");
875 assert_eq!(
876 scan_end,
877 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
878 );
879 }
880
881 #[fuchsia::test(allow_stalls = false)]
882 async fn client_send_scan_end_on_passive_scan_fails() {
883 let mut m = MockObjects::new().await;
884 m.fake_device_state.lock().config.start_passive_scan_fails = true;
885 let mut me = m.make_mlme().await;
886
887 me.make_client_station();
888 me.on_sme_scan(scan_req()).await;
889 let scan_end = m
890 .fake_device_state
891 .lock()
892 .next_mlme_msg::<fidl_mlme::ScanEnd>()
893 .expect("error reading MLME ScanEnd");
894 assert_eq!(
895 scan_end,
896 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::NotSupported }
897 );
898 }
899
900 #[fuchsia::test(allow_stalls = false)]
901 async fn mlme_respond_to_query_device_info() {
902 let mut mock_objects = MockObjects::new().await;
903 let mut mlme = mock_objects.make_mlme().await;
904
905 let (responder, receiver) = Responder::new();
906 mlme.handle_mlme_request(wlan_sme::MlmeRequest::QueryDeviceInfo(responder))
907 .await
908 .expect("Failed to send MlmeRequest::Connect");
909 assert_eq!(
910 receiver.await.unwrap(),
911 fidl_mlme::DeviceInfo {
912 sta_addr: IFACE_MAC.to_array(),
913 factory_addr: IFACE_MAC.to_array(),
914 role: fidl_common::WlanMacRole::Client,
915 bands: test_utils::fake_mlme_band_caps(),
916 softmac_hardware_capability: 0,
917 qos_capable: false,
918 }
919 );
920 }
921
922 #[fuchsia::test(allow_stalls = false)]
923 async fn mlme_respond_to_query_mac_sublayer_support() {
924 let mut m = MockObjects::new().await;
925 let mut me = m.make_mlme().await;
926
927 let (responder, receiver) = Responder::new();
928 me.handle_mlme_request(wlan_sme::MlmeRequest::QueryMacSublayerSupport(responder))
929 .await
930 .expect("Failed to send MlmeRequest::Connect");
931 let resp = receiver.await.unwrap();
932 assert_eq!(resp.rate_selection_offload.unwrap().supported, Some(false));
933 assert_eq!(
934 resp.data_plane.unwrap().data_plane_type,
935 Some(fidl_common::DataPlaneType::EthernetDevice)
936 );
937 assert_eq!(resp.device.as_ref().unwrap().is_synthetic, Some(true));
938 assert_eq!(
939 resp.device.as_ref().unwrap().mac_implementation_type,
940 Some(fidl_common::MacImplementationType::Softmac)
941 );
942 assert_eq!(resp.device.unwrap().tx_status_report_supported, Some(true));
943 }
944
945 #[fuchsia::test(allow_stalls = false)]
946 async fn mlme_respond_to_query_security_support() {
947 let mut m = MockObjects::new().await;
948 let mut me = m.make_mlme().await;
949
950 let (responder, receiver) = Responder::new();
951 assert_matches!(
952 me.handle_mlme_request(wlan_sme::MlmeRequest::QuerySecuritySupport(responder)).await,
953 Ok(())
954 );
955 let resp = receiver.await.unwrap();
956 assert_eq!(resp.mfp.unwrap().supported, Some(false));
957 assert_eq!(resp.sae.as_ref().unwrap().driver_handler_supported, Some(false));
958 assert_eq!(resp.sae.unwrap().sme_handler_supported, Some(false));
959 }
960
961 #[fuchsia::test(allow_stalls = false)]
962 async fn mlme_respond_to_query_spectrum_management_support() {
963 let mut m = MockObjects::new().await;
964 let mut me = m.make_mlme().await;
965
966 let (responder, receiver) = Responder::new();
967 me.handle_mlme_request(wlan_sme::MlmeRequest::QuerySpectrumManagementSupport(responder))
968 .await
969 .expect("Failed to send MlmeRequest::QuerySpectrumManagementSupport");
970 assert_eq!(receiver.await.unwrap().dfs.unwrap().supported, Some(true));
971 }
972
973 #[fuchsia::test(allow_stalls = false)]
974 async fn mlme_connect_unprotected_happy_path() {
975 let mut m = MockObjects::new().await;
976 let mut me = m.make_mlme().await;
977 let channel = Channel::new(6, Bandwidth::Cbw40, fidl_ieee80211::WlanBand::TwoGhz);
978 let connect_req = fidl_mlme::ConnectRequest {
979 selected_bss: fake_fidl_bss_description!(Open,
980 ssid: Ssid::try_from("ssid").unwrap().into(),
981 bssid: BSSID.to_array(),
982 channel: channel.clone(),
983 ),
984 connect_failure_timeout: 100,
985 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
986 sae_password: vec![],
987 wep_key: None,
988 security_ie: vec![],
989 owe_public_key: None,
990 };
991 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
992 .await
993 .expect("Failed to send MlmeRequest::Connect");
994
995 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
997 assert_eq!(ids.len(), 1);
998 });
999
1000 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1002 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1003 #[rustfmt::skip]
1004 let expected = vec![
1005 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, ];
1017 assert_eq!(&frame[..], &expected[..]);
1018
1019 #[rustfmt::skip]
1021 let auth_resp_success = vec![
1022 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, ];
1034 me.handle_mac_frame_rx(
1035 &auth_resp_success[..],
1036 MockWlanRxInfo::with_channel(channel.into()).into(),
1037 0.into(),
1038 )
1039 .await;
1040
1041 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1043 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1044 #[rustfmt::skip]
1045 let expected = vec![
1046 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, ];
1068 assert_eq!(&frame[..], &expected[..]);
1069
1070 #[rustfmt::skip]
1072 let assoc_resp_success = vec![
1073 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,
1087 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1091 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ];
1095 me.handle_mac_frame_rx(
1096 &assoc_resp_success[..],
1097 MockWlanRxInfo::with_channel(channel.into()).into(),
1098 0.into(),
1099 )
1100 .await;
1101
1102 let msg = m
1104 .fake_device_state
1105 .lock()
1106 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1107 .expect("expect ConnectConf");
1108 assert_eq!(
1109 msg,
1110 fidl_mlme::ConnectConfirm {
1111 peer_sta_address: BSSID.to_array(),
1112 result_code: fidl_ieee80211::StatusCode::Success,
1113 association_id: 42,
1114 association_ies: vec![
1115 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
1118 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1122 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
1126 }
1127 );
1128
1129 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
1131 }
1132
1133 #[fuchsia::test(allow_stalls = false)]
1134 async fn mlme_connect_protected_happy_path() {
1135 let mut m = MockObjects::new().await;
1136 let mut me = m.make_mlme().await;
1137 let channel = Channel::new(6, Bandwidth::Cbw40, fidl_ieee80211::WlanBand::TwoGhz);
1138 let connect_req = fidl_mlme::ConnectRequest {
1139 selected_bss: fake_fidl_bss_description!(Wpa2,
1140 ssid: Ssid::try_from("ssid").unwrap().into(),
1141 bssid: BSSID.to_array(),
1142 channel: channel.clone(),
1143 ),
1144 connect_failure_timeout: 100,
1145 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1146 sae_password: vec![],
1147 wep_key: None,
1148 security_ie: vec![
1149 48, 18, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 2, ],
1155 owe_public_key: None,
1156 };
1157 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1158 .await
1159 .expect("Failed to send MlmeRequest::Connect");
1160
1161 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
1163 assert_eq!(ids.len(), 1);
1164 });
1165
1166 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1168 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1169 #[rustfmt::skip]
1170 let expected = vec![
1171 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, ];
1183 assert_eq!(&frame[..], &expected[..]);
1184
1185 #[rustfmt::skip]
1187 let auth_resp_success = vec![
1188 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, ];
1200 me.handle_mac_frame_rx(
1201 &auth_resp_success[..],
1202 MockWlanRxInfo::with_channel(channel.into()).into(),
1203 0.into(),
1204 )
1205 .await;
1206
1207 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1209 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1210 #[rustfmt::skip]
1211 let expected = vec![
1212 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, ];
1239 assert_eq!(&frame[..], &expected[..]);
1240
1241 #[rustfmt::skip]
1243 let assoc_resp_success = vec![
1244 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,
1258 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, ];
1271 me.handle_mac_frame_rx(
1272 &assoc_resp_success[..],
1273 MockWlanRxInfo::with_channel(channel.into()).into(),
1274 0.into(),
1275 )
1276 .await;
1277
1278 let msg = m
1280 .fake_device_state
1281 .lock()
1282 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1283 .expect("expect ConnectConf");
1284 assert_eq!(
1285 msg,
1286 fidl_mlme::ConnectConfirm {
1287 peer_sta_address: BSSID.to_array(),
1288 result_code: fidl_ieee80211::StatusCode::Success,
1289 association_id: 42,
1290 association_ies: vec![
1291 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,
1302 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
1307 }
1308 );
1309
1310 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::DOWN);
1312
1313 me.handle_mlme_request(wlan_sme::MlmeRequest::SetCtrlPort(
1315 fidl_mlme::SetControlledPortRequest {
1316 peer_sta_address: BSSID.to_array(),
1317 state: fidl_mlme::ControlledPortState::Open,
1318 },
1319 ))
1320 .await
1321 .expect("expect sending msg to succeed");
1322
1323 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
1325 }
1326
1327 #[fuchsia::test(allow_stalls = false)]
1328 async fn mlme_connect_vht() {
1329 let mut m = MockObjects::new().await;
1330 let mut me = m.make_mlme().await;
1331 let channel = Channel::new(36, Bandwidth::Cbw40, fidl_ieee80211::WlanBand::FiveGhz);
1332 let connect_req = fidl_mlme::ConnectRequest {
1333 selected_bss: fake_fidl_bss_description!(Open,
1334 ssid: Ssid::try_from("ssid").unwrap().into(),
1335 bssid: BSSID.to_array(),
1336 channel: channel.clone(),
1337 ),
1338 connect_failure_timeout: 100,
1339 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1340 sae_password: vec![],
1341 wep_key: None,
1342 security_ie: vec![],
1343 owe_public_key: None,
1344 };
1345 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1346 .await
1347 .expect("Failed to send MlmeRequest::Connect.");
1348
1349 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
1351 assert_eq!(ids.len(), 1);
1352 });
1353
1354 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1356 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1357
1358 #[rustfmt::skip]
1360 let auth_resp_success = vec![
1361 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, ];
1373 me.handle_mac_frame_rx(
1374 &auth_resp_success[..],
1375 MockWlanRxInfo::with_channel(channel.into()).into(),
1376 0.into(),
1377 )
1378 .await;
1379
1380 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1382 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1383 #[rustfmt::skip]
1384 let expected = vec![
1385 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, ];
1407 assert_eq!(&frame[..], &expected[..]);
1408 }
1409
1410 #[fuchsia::test(allow_stalls = false)]
1411 async fn mlme_connect_timeout() {
1412 let mut m = MockObjects::new().await;
1413 let mut me = m.make_mlme().await;
1414 let connect_req = fidl_mlme::ConnectRequest {
1415 selected_bss: fake_fidl_bss_description!(Open, bssid: BSSID.to_array()),
1416 connect_failure_timeout: 100,
1417 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1418 sae_password: vec![],
1419 wep_key: None,
1420 security_ie: vec![],
1421 owe_public_key: None,
1422 };
1423 me.handle_mlme_request(wlan_sme::MlmeRequest::Connect(connect_req))
1424 .await
1425 .expect("Failed to send MlmeRequest::Connect.");
1426
1427 let (event, _id) = assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(events) => {
1429 assert_eq!(events.len(), 1);
1430 events[0].clone()
1431 });
1432
1433 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1435 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
1436
1437 me.handle_timeout(event).await;
1439
1440 let msg = m
1442 .fake_device_state
1443 .lock()
1444 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1445 .expect("expect msg");
1446 assert_eq!(
1447 msg,
1448 fidl_mlme::ConnectConfirm {
1449 peer_sta_address: BSSID.to_array(),
1450 result_code: fidl_ieee80211::StatusCode::RejectedSequenceTimeout,
1451 association_id: 0,
1452 association_ies: vec![],
1453 },
1454 );
1455 }
1456
1457 #[fuchsia::test(allow_stalls = false)]
1458 async fn mlme_reconnect_no_sta() {
1459 let mut m = MockObjects::new().await;
1460 let mut me = m.make_mlme().await;
1461
1462 let reconnect_req = fidl_mlme::ReconnectRequest { peer_sta_address: [1, 2, 3, 4, 5, 6] };
1463 let result = me.handle_mlme_request(wlan_sme::MlmeRequest::Reconnect(reconnect_req)).await;
1464 let err = result.unwrap_err();
1465 let mlme_err = err.downcast_ref::<Error>().expect("expected Mlme Error");
1466 assert_matches!(mlme_err, Error::Status(_, zx::Status::BAD_STATE));
1467
1468 let msg = m
1470 .fake_device_state
1471 .lock()
1472 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
1473 .expect("expect msg");
1474 assert_eq!(
1475 msg,
1476 fidl_mlme::ConnectConfirm {
1477 peer_sta_address: [1, 2, 3, 4, 5, 6],
1478 result_code: fidl_ieee80211::StatusCode::DeniedNoAssociationExists,
1479 association_id: 0,
1480 association_ies: vec![],
1481 },
1482 );
1483 }
1484
1485 #[fuchsia::test(allow_stalls = false)]
1486 async fn mlme_respond_to_get_iface_stats_with_error_status() {
1487 let mut m = MockObjects::new().await;
1488 let mut me = m.make_mlme().await;
1489
1490 let (responder, receiver) = Responder::new();
1491 me.handle_mlme_request(wlan_sme::MlmeRequest::GetIfaceStats(responder))
1492 .await
1493 .expect("Failed to send MlmeRequest::GetIfaceStats.");
1494 assert_eq!(
1495 receiver.await,
1496 Ok(fidl_mlme::GetIfaceStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED))
1497 );
1498 }
1499
1500 #[fuchsia::test(allow_stalls = false)]
1501 async fn mlme_respond_to_get_iface_histogram_stats_with_error_status() {
1502 let mut m = MockObjects::new().await;
1503 let mut me = m.make_mlme().await;
1504
1505 let (responder, receiver) = Responder::new();
1506 me.handle_mlme_request(wlan_sme::MlmeRequest::GetIfaceHistogramStats(responder))
1507 .await
1508 .expect("Failed to send MlmeRequest::GetIfaceHistogramStats");
1509 assert_eq!(
1510 receiver.await,
1511 Ok(fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(
1512 zx::sys::ZX_ERR_NOT_SUPPORTED
1513 ))
1514 );
1515 }
1516
1517 #[test]
1518 fn drop_mgmt_frame_wrong_bssid() {
1519 let frame = [
1520 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0x10, 0, ];
1528 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1529 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1530 }
1531
1532 #[test]
1533 fn drop_mgmt_frame_wrong_dst_addr() {
1534 let frame = [
1535 0b11010000, 0b00000000, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1543 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1544 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1545 }
1546
1547 #[test]
1548 fn mgmt_frame_ok_broadcast() {
1549 let frame = [
1550 0b11010000, 0b00000000, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1558 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1559 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1560 }
1561
1562 #[test]
1563 fn mgmt_frame_ok_client_addr() {
1564 let frame = [
1565 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1573 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1574 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1575 }
1576
1577 #[test]
1578 fn drop_data_frame_wrong_bssid() {
1579 let frame = [
1580 0b01001000,
1582 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1589 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1590 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1591 }
1592
1593 #[test]
1594 fn drop_data_frame_wrong_dst_addr() {
1595 let frame = [
1596 0b01001000,
1598 0b00000010, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1605 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1606 assert_eq!(false, make_client_station().should_handle_frame(&frame));
1607 }
1608
1609 #[test]
1610 fn data_frame_ok_broadcast() {
1611 let frame = [
1612 0b01001000,
1614 0b00000010, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1621 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1622 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1623 }
1624
1625 #[test]
1626 fn data_frame_ok_client_addr() {
1627 let frame = [
1628 0b01001000,
1630 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
1637 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
1638 assert_eq!(true, make_client_station().should_handle_frame(&frame));
1639 }
1640}