1mod channel_switch;
6mod convert_beacon;
7mod lost_bss;
8mod scanner;
9mod state;
10#[cfg(test)]
11mod test_utils;
12
13use crate::block_ack::BlockAckTx;
14use crate::device::{self, DeviceOps};
15use crate::disconnect::LocallyInitiated;
16use crate::error::Error;
17use crate::{akm_algorithm, ddk_converter};
18use anyhow::format_err;
19use channel_switch::ChannelState;
20use fdf::{Arena, ArenaBox, ArenaStaticBox};
21use ieee80211::{Bssid, MacAddr, MacAddrBytes, Ssid};
22use log::{error, warn};
23use scanner::Scanner;
24use state::States;
25use std::mem;
26use std::ptr::NonNull;
27use wlan_common::append::Append;
28use wlan_common::bss::BssDescription;
29use wlan_common::buffer_writer::BufferWriter;
30use wlan_common::capabilities::{ClientCapabilities, derive_join_capabilities};
31use wlan_common::channel::Channel;
32use wlan_common::ie::rsn::rsne;
33use wlan_common::ie::{self, Id};
34use wlan_common::mac::{self, Aid, CapabilityInfo};
35use wlan_common::sequence::SequenceManager;
36use wlan_common::time::TimeUnit;
37use wlan_common::timer::{EventHandle, Timer};
38use wlan_common::{data_writer, mgmt_writer, wmm};
39use wlan_frame_writer::{append_frame_to, write_frame, write_frame_with_fixed_slice};
40use zerocopy::SplitByteSlice;
41use {
42 fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211,
43 fidl_fuchsia_wlan_minstrel as fidl_minstrel, fidl_fuchsia_wlan_mlme as fidl_mlme,
44 fidl_fuchsia_wlan_softmac as fidl_softmac, fuchsia_trace as trace, wlan_trace as wtrace,
45};
46
47pub use scanner::ScanError;
48
49#[derive(Debug, Clone, PartialEq)]
50pub enum TimedEvent {
51 Connecting,
53 Reassociating,
55 AssociationStatusCheck,
58 ChannelSwitch,
60}
61
62#[cfg(test)]
63impl TimedEvent {
64 fn class(&self) -> TimedEventClass {
65 match self {
66 Self::Connecting => TimedEventClass::Connecting,
67 Self::Reassociating => TimedEventClass::Reassociating,
68 Self::AssociationStatusCheck => TimedEventClass::AssociationStatusCheck,
69 Self::ChannelSwitch => TimedEventClass::ChannelSwitch,
70 }
71 }
72}
73
74#[cfg(test)]
75#[derive(Debug, PartialEq, Eq, Hash)]
76pub enum TimedEventClass {
77 Connecting,
78 Reassociating,
79 AssociationStatusCheck,
80 ChannelSwitch,
81}
82
83#[repr(C)]
86#[derive(Debug, Clone, Default)]
87pub struct ClientConfig {
88 pub ensure_on_channel_time: zx::sys::zx_duration_t,
89}
90
91pub struct Context<D> {
92 _config: ClientConfig,
93 device: D,
94 timer: Timer<TimedEvent>,
95 seq_mgr: SequenceManager,
96}
97
98pub struct ClientMlme<D> {
99 sta: Option<Client>,
100 ctx: Context<D>,
101 scanner: Scanner,
102 channel_state: ChannelState,
103}
104
105impl<D: DeviceOps> crate::MlmeImpl for ClientMlme<D> {
106 type Config = ClientConfig;
107 type Device = D;
108 type TimerEvent = TimedEvent;
109 async fn new(
110 config: Self::Config,
111 device: Self::Device,
112 timer: Timer<TimedEvent>,
113 ) -> Result<Self, anyhow::Error> {
114 Self::new(config, device, timer).await.map_err(From::from)
115 }
116 async fn handle_mlme_request(
117 &mut self,
118 req: wlan_sme::MlmeRequest,
119 ) -> Result<(), anyhow::Error> {
120 Self::handle_mlme_req(self, req).await.map_err(From::from)
121 }
122 async fn handle_mac_frame_rx(
123 &mut self,
124 bytes: &[u8],
125 rx_info: fidl_softmac::WlanRxInfo,
126 async_id: trace::Id,
127 ) {
128 wtrace::duration!(c"ClientMlme::handle_mac_frame_rx");
129 Self::on_mac_frame_rx(self, bytes, rx_info, async_id).await
130 }
131 fn handle_eth_frame_tx(
132 &mut self,
133 bytes: &[u8],
134 async_id: trace::Id,
135 ) -> Result<(), anyhow::Error> {
136 wtrace::duration!(c"ClientMlme::handle_eth_frame_tx");
137 Self::on_eth_frame_tx(self, bytes, async_id).map_err(From::from)
138 }
139 async fn handle_scan_complete(&mut self, status: zx::Status, scan_id: u64) {
140 Self::handle_scan_complete(self, status, scan_id).await;
141 }
142 async fn handle_timeout(&mut self, event: TimedEvent) {
143 Self::handle_timed_event(self, event).await
144 }
145 fn access_device(&mut self) -> &mut Self::Device {
146 &mut self.ctx.device
147 }
148}
149
150impl<D> ClientMlme<D> {
151 pub fn seq_mgr(&mut self) -> &mut SequenceManager {
152 &mut self.ctx.seq_mgr
153 }
154
155 fn on_sme_get_iface_stats(
156 &self,
157 responder: wlan_sme::responder::Responder<fidl_mlme::GetIfaceStatsResponse>,
158 ) -> Result<(), Error> {
159 let resp = fidl_mlme::GetIfaceStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED);
161 responder.respond(resp);
162 Ok(())
163 }
164
165 fn on_sme_get_iface_histogram_stats(
166 &self,
167 responder: wlan_sme::responder::Responder<fidl_mlme::GetIfaceHistogramStatsResponse>,
168 ) -> Result<(), Error> {
169 let resp =
171 fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED);
172 responder.respond(resp);
173 Ok(())
174 }
175
176 fn on_sme_list_minstrel_peers(
177 &self,
178 responder: wlan_sme::responder::Responder<fidl_mlme::MinstrelListResponse>,
179 ) -> Result<(), Error> {
180 error!("ListMinstrelPeers is not supported.");
182 let peers = fidl_minstrel::Peers { addrs: vec![] };
183 let resp = fidl_mlme::MinstrelListResponse { peers };
184 responder.respond(resp);
185 Ok(())
186 }
187
188 fn on_sme_get_minstrel_stats(
189 &self,
190 responder: wlan_sme::responder::Responder<fidl_mlme::MinstrelStatsResponse>,
191 _addr: &MacAddr,
192 ) -> Result<(), Error> {
193 error!("GetMinstrelStats is not supported.");
195 let resp = fidl_mlme::MinstrelStatsResponse { peer: None };
196 responder.respond(resp);
197 Ok(())
198 }
199}
200
201impl<D: DeviceOps> ClientMlme<D> {
202 pub async fn new(
203 config: ClientConfig,
204 mut device: D,
205 timer: Timer<TimedEvent>,
206 ) -> Result<Self, Error> {
207 let iface_mac = device::try_query_iface_mac(&mut device).await?;
208 Ok(Self {
209 sta: None,
210 ctx: Context { _config: config, device, timer, seq_mgr: SequenceManager::new() },
211 scanner: Scanner::new(iface_mac.into()),
212 channel_state: Default::default(),
213 })
214 }
215
216 pub async fn set_main_channel(
217 &mut self,
218 channel: fidl_ieee80211::WlanChannel,
219 ) -> Result<(), zx::Status> {
220 self.channel_state.bind(&mut self.ctx, &mut self.scanner).set_main_channel(channel).await
221 }
222
223 pub async fn on_mac_frame_rx(
224 &mut self,
225 frame: &[u8],
226 rx_info: fidl_softmac::WlanRxInfo,
227 async_id: trace::Id,
228 ) {
229 wtrace::duration!(c"ClientMlme::on_mac_frame_rx");
230 if let Some(mgmt_frame) = mac::MgmtFrame::parse(frame, false) {
232 let bssid = Bssid::from(mgmt_frame.mgmt_hdr.addr3);
233 match mgmt_frame.try_into_mgmt_body().1 {
234 Some(mac::MgmtBody::Beacon { bcn_hdr, elements }) => {
235 wtrace::duration!(c"MgmtBody::Beacon");
236 self.scanner.bind(&mut self.ctx).handle_ap_advertisement(
237 bssid,
238 bcn_hdr.beacon_interval,
239 bcn_hdr.capabilities,
240 elements,
241 rx_info.clone(),
242 );
243 }
244 Some(mac::MgmtBody::ProbeResp { probe_resp_hdr, elements }) => {
245 wtrace::duration!(c"MgmtBody::ProbeResp");
246 self.scanner.bind(&mut self.ctx).handle_ap_advertisement(
247 bssid,
248 probe_resp_hdr.beacon_interval,
249 probe_resp_hdr.capabilities,
250 elements,
251 rx_info.clone(),
252 )
253 }
254 _ => (),
255 }
256 }
257
258 if let Some(sta) = self.sta.as_mut() {
259 match self.channel_state.get_main_channel() {
263 Some(main_channel) if main_channel.primary == rx_info.channel.primary => {
264 sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
265 .on_mac_frame(frame, rx_info, async_id)
266 .await
267 }
268 Some(_) => {
269 wtrace::async_end_wlansoftmac_rx(async_id, "off main channel");
270 }
271 None => {
274 error!(
275 "Received MAC frame on channel {:?} while main channel is not set.",
276 rx_info.channel
277 );
278 wtrace::async_end_wlansoftmac_rx(async_id, "main channel not set");
279 }
280 }
281 } else {
282 wtrace::async_end_wlansoftmac_rx(async_id, "no bound client");
283 }
284 }
285
286 pub async fn handle_mlme_req(&mut self, req: wlan_sme::MlmeRequest) -> Result<(), Error> {
287 use wlan_sme::MlmeRequest as Req;
288
289 match req {
290 Req::Scan(req) => Ok(self.on_sme_scan(req).await),
292 Req::Connect(req) => self.on_sme_connect(req).await,
293 Req::GetIfaceStats(responder) => self.on_sme_get_iface_stats(responder),
294 Req::GetIfaceHistogramStats(responder) => {
295 self.on_sme_get_iface_histogram_stats(responder)
296 }
297 Req::QueryDeviceInfo(responder) => self.on_sme_query_device_info(responder).await,
298 Req::QueryMacSublayerSupport(responder) => {
299 self.on_sme_query_mac_sublayer_support(responder).await
300 }
301 Req::QuerySecuritySupport(responder) => {
302 self.on_sme_query_security_support(responder).await
303 }
304 Req::QuerySpectrumManagementSupport(responder) => {
305 self.on_sme_query_spectrum_management_support(responder).await
306 }
307 Req::ListMinstrelPeers(responder) => self.on_sme_list_minstrel_peers(responder),
308 Req::GetMinstrelStats(req, responder) => {
309 self.on_sme_get_minstrel_stats(responder, &req.peer_addr.into())
310 }
311 other_message => match &mut self.sta {
312 None => {
313 if let Req::Reconnect(req) = other_message {
314 self.ctx.device.send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf {
315 resp: fidl_mlme::ConnectConfirm {
316 peer_sta_address: req.peer_sta_address,
317 result_code: fidl_ieee80211::StatusCode::DeniedNoAssociationExists,
318 association_id: 0,
319 association_ies: vec![],
320 },
321 })?;
322 }
323 Err(Error::Status(
324 format!(
325 "Failed to handle {} MLME request when this ClientMlme has no sta.",
326 other_message.name()
327 ),
328 zx::Status::BAD_STATE,
329 ))
330 }
331 Some(sta) => Ok(sta
332 .bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
333 .handle_mlme_req(other_message)
334 .await),
335 },
336 }
337 }
338
339 async fn on_sme_scan(&mut self, req: fidl_mlme::ScanRequest) {
340 let txn_id = req.txn_id;
341 let _ = self.scanner.bind(&mut self.ctx).on_sme_scan(req).await.map_err(|e| {
342 error!("Scan failed in MLME: {:?}", e);
343 let code = match e {
344 Error::ScanError(scan_error) => scan_error.into(),
345 _ => fidl_mlme::ScanResultCode::InternalError,
346 };
347 self.ctx
348 .device
349 .send_mlme_event(fidl_mlme::MlmeEvent::OnScanEnd {
350 end: fidl_mlme::ScanEnd { txn_id, code },
351 })
352 .unwrap_or_else(|e| error!("error sending MLME ScanEnd: {}", e));
353 });
354 }
355
356 pub async fn handle_scan_complete(&mut self, status: zx::Status, scan_id: u64) {
357 self.scanner.bind(&mut self.ctx).handle_scan_complete(status, scan_id).await;
358 }
359
360 async fn on_sme_connect(&mut self, req: fidl_mlme::ConnectRequest) -> Result<(), Error> {
361 if let Err(e) = self.scanner.bind(&mut self.ctx).cancel_ongoing_scan().await {
364 warn!("Failed to cancel ongoing scan before connect: {}.", e);
365 }
366
367 let bssid = req.selected_bss.bssid;
368 let result = match req.selected_bss.try_into() {
369 Ok(bss) => {
370 let req = ParsedConnectRequest {
371 selected_bss: bss,
372 connect_failure_timeout: req.connect_failure_timeout,
373 auth_type: req.auth_type,
374 sae_password: req.sae_password,
375 wep_key: req.wep_key.map(|k| *k),
376 security_ie: req.security_ie,
377 };
378 self.join_device(&req.selected_bss).await.map(|cap| (req, cap))
379 }
380 Err(e) => Err(Error::Status(
381 format!("Error parsing BssDescription: {:?}", e),
382 zx::Status::IO_INVALID,
383 )),
384 };
385
386 match result {
387 Ok((req, client_capabilities)) => {
388 self.sta.replace(Client::new(
389 req,
390 device::try_query_iface_mac(&mut self.ctx.device).await?,
391 client_capabilities,
392 ));
393 if let Some(sta) = &mut self.sta {
394 sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
395 .start_connecting()
396 .await;
397 }
398 Ok(())
399 }
400 Err(e) => {
401 error!("Error setting up device for join: {}", e);
402 self.ctx.device.send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf {
405 resp: fidl_mlme::ConnectConfirm {
406 peer_sta_address: bssid,
407 result_code: fidl_ieee80211::StatusCode::JoinFailure,
408 association_id: 0,
409 association_ies: vec![],
410 },
411 })?;
412 Err(e)
413 }
414 }
415 }
416
417 async fn join_device(&mut self, bss: &BssDescription) -> Result<ClientCapabilities, Error> {
418 let info = ddk_converter::mlme_device_info_from_softmac(
419 device::try_query(&mut self.ctx.device).await?,
420 )?;
421 let join_caps = derive_join_capabilities(Channel::from(bss.channel), bss.rates(), &info)
422 .map_err(|e| {
423 Error::Status(
424 format!("Failed to derive join capabilities: {:?}", e),
425 zx::Status::NOT_SUPPORTED,
426 )
427 })?;
428
429 self.set_main_channel(bss.channel.into())
430 .await
431 .map_err(|status| Error::Status(format!("Error setting device channel"), status))?;
432
433 let join_bss_request = fidl_common::JoinBssRequest {
434 bssid: Some(bss.bssid.to_array()),
435 bss_type: Some(fidl_common::BssType::Infrastructure),
436 remote: Some(true),
437 beacon_period: Some(bss.beacon_period),
438 ..Default::default()
439 };
440
441 self.ctx
443 .device
444 .join_bss(&join_bss_request)
445 .await
446 .map(|()| join_caps)
447 .map_err(|status| Error::Status(format!("Error setting BSS in driver"), status))
448 }
449
450 async fn on_sme_query_device_info(
451 &mut self,
452 responder: wlan_sme::responder::Responder<fidl_mlme::DeviceInfo>,
453 ) -> Result<(), Error> {
454 let info = ddk_converter::mlme_device_info_from_softmac(
455 device::try_query(&mut self.ctx.device).await?,
456 )?;
457 responder.respond(info);
458 Ok(())
459 }
460
461 async fn on_sme_query_mac_sublayer_support(
462 &mut self,
463 responder: wlan_sme::responder::Responder<fidl_common::MacSublayerSupport>,
464 ) -> Result<(), Error> {
465 let support = device::try_query_mac_sublayer_support(&mut self.ctx.device).await?;
466 responder.respond(support);
467 Ok(())
468 }
469
470 async fn on_sme_query_security_support(
471 &mut self,
472 responder: wlan_sme::responder::Responder<fidl_common::SecuritySupport>,
473 ) -> Result<(), Error> {
474 let support = device::try_query_security_support(&mut self.ctx.device).await?;
475 responder.respond(support);
476 Ok(())
477 }
478
479 async fn on_sme_query_spectrum_management_support(
480 &mut self,
481 responder: wlan_sme::responder::Responder<fidl_common::SpectrumManagementSupport>,
482 ) -> Result<(), Error> {
483 let support = device::try_query_spectrum_management_support(&mut self.ctx.device).await?;
484 responder.respond(support);
485 Ok(())
486 }
487
488 pub fn on_eth_frame_tx<B: SplitByteSlice>(
489 &mut self,
490 bytes: B,
491 async_id: trace::Id,
492 ) -> Result<(), Error> {
493 wtrace::duration!(c"ClientMlme::on_eth_frame_tx");
494 match self.sta.as_mut() {
495 None => Err(Error::Status(
496 format!("Ethernet frame dropped (Client does not exist)."),
497 zx::Status::BAD_STATE,
498 )),
499 Some(sta) => sta
500 .bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
501 .on_eth_frame_tx(bytes, async_id),
502 }
503 }
504
505 pub async fn handle_timed_event(&mut self, event: TimedEvent) {
508 if let Some(sta) = self.sta.as_mut() {
509 return sta
510 .bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
511 .handle_timed_event(event)
512 .await;
513 }
514 }
515}
516
517pub struct Client {
521 state: Option<States>,
522 pub connect_req: ParsedConnectRequest,
523 pub iface_mac: MacAddr,
524 pub client_capabilities: ClientCapabilities,
525 pub connect_timeout: Option<EventHandle>,
526}
527
528impl Client {
529 pub fn new(
530 connect_req: ParsedConnectRequest,
531 iface_mac: MacAddr,
532 client_capabilities: ClientCapabilities,
533 ) -> Self {
534 Self {
535 state: Some(States::new_initial()),
536 connect_req,
537 iface_mac,
538 client_capabilities,
539 connect_timeout: None,
540 }
541 }
542
543 pub fn ssid(&self) -> &Ssid {
544 &self.connect_req.selected_bss.ssid
545 }
546
547 pub fn bssid(&self) -> Bssid {
548 self.connect_req.selected_bss.bssid
549 }
550
551 pub fn beacon_period(&self) -> zx::MonotonicDuration {
552 zx::MonotonicDuration::from(TimeUnit(self.connect_req.selected_bss.beacon_period))
553 }
554
555 pub fn eapol_required(&self) -> bool {
556 self.connect_req.selected_bss.rsne().is_some()
557 || self.connect_req.selected_bss.find_wpa_ie().is_some()
561 }
562
563 pub fn bind<'a, D>(
564 &'a mut self,
565 ctx: &'a mut Context<D>,
566 scanner: &'a mut Scanner,
567 channel_state: &'a mut ChannelState,
568 ) -> BoundClient<'a, D> {
569 BoundClient { sta: self, ctx, scanner, channel_state }
570 }
571
572 fn should_handle_frame<B: SplitByteSlice>(&self, mac_frame: &mac::MacFrame<B>) -> bool {
576 wtrace::duration!(c"Client::should_handle_frame");
577
578 let (src_addr, dst_addr) = match mac_frame {
581 mac::MacFrame::Mgmt(mac::MgmtFrame { mgmt_hdr, .. }) => {
582 (Some(mgmt_hdr.addr3), mgmt_hdr.addr1)
583 }
584 mac::MacFrame::Data(mac::DataFrame { fixed_fields, .. }) => {
585 (mac::data_bssid(&fixed_fields), mac::data_dst_addr(&fixed_fields))
586 }
587 _ => return false,
589 };
590 src_addr.is_some_and(|src_addr| src_addr == self.bssid().into())
591 && (!dst_addr.is_unicast() || dst_addr == self.iface_mac)
592 }
593}
594
595pub struct BoundClient<'a, D> {
596 sta: &'a mut Client,
597 ctx: &'a mut Context<D>,
599 scanner: &'a mut Scanner,
600 channel_state: &'a mut ChannelState,
601}
602
603impl<'a, D: DeviceOps> akm_algorithm::AkmAction for BoundClient<'a, D> {
604 fn send_auth_frame(
605 &mut self,
606 auth_type: mac::AuthAlgorithmNumber,
607 seq_num: u16,
608 result_code: mac::StatusCode,
609 auth_content: &[u8],
610 ) -> Result<(), anyhow::Error> {
611 self.send_auth_frame(auth_type, seq_num, result_code, auth_content).map_err(|e| e.into())
612 }
613
614 fn forward_sme_sae_rx(
615 &mut self,
616 seq_num: u16,
617 status_code: fidl_ieee80211::StatusCode,
618 sae_fields: Vec<u8>,
619 ) {
620 self.forward_sae_frame_rx(seq_num, status_code, sae_fields)
621 }
622
623 fn forward_sae_handshake_ind(&mut self) {
624 self.forward_sae_handshake_ind()
625 }
626}
627
628impl<'a, D: DeviceOps> BoundClient<'a, D> {
629 fn deliver_msdu<B: SplitByteSlice>(&mut self, msdu: mac::Msdu<B>) -> Result<(), Error> {
633 let mac::Msdu { dst_addr, src_addr, llc_frame } = msdu;
634
635 let mut packet = [0u8; mac::MAX_ETH_FRAME_LEN];
636 let (frame_start, frame_end) = write_frame_with_fixed_slice!(&mut packet[..], {
637 headers: {
638 mac::EthernetIIHdr: &mac::EthernetIIHdr {
639 da: dst_addr,
640 sa: src_addr,
641 ether_type: llc_frame.hdr.protocol_id,
642 },
643 },
644 payload: &llc_frame.body,
645 })?;
646 self.ctx
647 .device
648 .deliver_eth_frame(&packet[frame_start..frame_end])
649 .map_err(|s| Error::Status(format!("could not deliver Ethernet II frame"), s))
650 }
651
652 pub fn send_auth_frame(
653 &mut self,
654 auth_type: mac::AuthAlgorithmNumber,
655 seq_num: u16,
656 result_code: mac::StatusCode,
657 auth_content: &[u8],
658 ) -> Result<(), Error> {
659 let buffer = write_frame!({
660 headers: {
661 mac::MgmtHdr: &mgmt_writer::mgmt_hdr_to_ap(
662 mac::FrameControl(0)
663 .with_frame_type(mac::FrameType::MGMT)
664 .with_mgmt_subtype(mac::MgmtSubtype::AUTH),
665 self.sta.bssid(),
666 self.sta.iface_mac,
667 mac::SequenceControl(0)
668 .with_seq_num(self.ctx.seq_mgr.next_sns1(&self.sta.bssid().into()) as u16)
669 ),
670 mac::AuthHdr: &mac::AuthHdr {
671 auth_alg_num: auth_type,
672 auth_txn_seq_num: seq_num,
673 status_code: result_code,
674 },
675 },
676 body: auth_content,
677 })?;
678 self.send_mgmt_or_ctrl_frame(buffer)
679 .map_err(|s| Error::Status(format!("error sending open auth frame"), s))
680 }
681
682 pub fn send_open_auth_frame(&mut self) -> Result<(), Error> {
684 self.send_auth_frame(
685 mac::AuthAlgorithmNumber::OPEN,
686 1,
687 fidl_ieee80211::StatusCode::Success.into(),
688 &[],
689 )
690 }
691
692 pub fn send_assoc_req_frame(&mut self) -> Result<(), Error> {
694 let ssid = self.sta.ssid().clone();
695 let cap = &self.sta.client_capabilities.0;
696 let capability_info = cap.capability_info.0;
697 let rates: Vec<u8> = cap.rates.iter().map(|r| r.rate()).collect();
698 let ht_cap = cap.ht_cap;
699 let vht_cap = cap.vht_cap;
700 let security_ie = self.sta.connect_req.security_ie.clone();
701
702 let rsne = (!security_ie.is_empty() && security_ie[0] == ie::Id::RSNE.0)
703 .then(|| match rsne::from_bytes(&security_ie[..]) {
704 Ok((_, x)) => Ok(x),
705 Err(e) => Err(format_err!("error parsing rsne {:?} : {:?}", security_ie, e)),
706 })
707 .transpose()?;
708 let buffer = write_frame!({
709 headers: {
710 mac::MgmtHdr: &mgmt_writer::mgmt_hdr_to_ap(
711 mac::FrameControl(0)
712 .with_frame_type(mac::FrameType::MGMT)
713 .with_mgmt_subtype(mac::MgmtSubtype::ASSOC_REQ),
714 self.sta.bssid(),
715 self.sta.iface_mac,
716 mac::SequenceControl(0)
717 .with_seq_num(self.ctx.seq_mgr.next_sns1(&self.sta.bssid().into()) as u16)
718 ),
719 mac::AssocReqHdr: &mac::AssocReqHdr {
720 capabilities: mac::CapabilityInfo(capability_info),
721 listen_interval: 0,
722 },
723 },
724 ies: {
725 ssid: ssid,
726 supported_rates: rates,
727 extended_supported_rates: {},
728 rsne?: rsne,
729 ht_cap?: ht_cap,
730 vht_cap?: vht_cap,
731 },
732 })?;
733 self.send_mgmt_or_ctrl_frame(buffer)
734 .map_err(|s| Error::Status(format!("error sending assoc req frame"), s))
735 }
736
737 fn send_keep_alive_resp_frame(&mut self) -> Result<(), Error> {
743 let buffer = write_frame!({
744 headers: {
745 mac::FixedDataHdrFields: &data_writer::data_hdr_client_to_ap(
746 mac::FrameControl(0)
747 .with_frame_type(mac::FrameType::DATA)
748 .with_data_subtype(mac::DataSubtype(0).with_null(true)),
749 self.sta.bssid(),
750 self.sta.iface_mac,
751 mac::SequenceControl(0)
752 .with_seq_num(self.ctx.seq_mgr.next_sns1(&self.sta.bssid().into()) as u16)
753 ),
754 },
755 })?;
756 self.ctx
757 .device
758 .send_wlan_frame(buffer, fidl_softmac::WlanTxInfoFlags::empty(), None)
759 .map_err(|s| Error::Status(format!("error sending keep alive frame"), s))
760 }
761
762 pub fn send_deauth_frame(&mut self, reason_code: mac::ReasonCode) -> Result<(), Error> {
763 let buffer = write_frame!({
764 headers: {
765 mac::MgmtHdr: &mgmt_writer::mgmt_hdr_to_ap(
766 mac::FrameControl(0)
767 .with_frame_type(mac::FrameType::MGMT)
768 .with_mgmt_subtype(mac::MgmtSubtype::DEAUTH),
769 self.sta.bssid(),
770 self.sta.iface_mac,
771 mac::SequenceControl(0)
772 .with_seq_num(self.ctx.seq_mgr.next_sns1(&self.sta.bssid().into()) as u16)
773 ),
774 mac::DeauthHdr: &mac::DeauthHdr {
775 reason_code,
776 },
777 },
778 })?;
779 let result = self
780 .send_mgmt_or_ctrl_frame(buffer)
781 .map_err(|s| Error::Status(format!("error sending deauthenticate frame"), s));
782 self.channel_state.bind(&mut self.ctx, &mut self.scanner).clear_main_channel();
784
785 result
786 }
787
788 pub fn send_data_frame(
792 &mut self,
793 src: MacAddr,
794 dst: MacAddr,
795 is_protected: bool,
796 qos_ctrl: bool,
797 ether_type: u16,
798 payload: &[u8],
799 async_id: Option<trace::Id>,
800 ) -> Result<(), Error> {
801 let async_id_provided = async_id.is_some();
802 let async_id = async_id.unwrap_or_else(|| {
803 let async_id = trace::Id::new();
804 wtrace::async_begin_wlansoftmac_tx(async_id, "mlme");
805 async_id
806 });
807 wtrace::duration!(c"BoundClient::send_data_frame");
808
809 let qos_ctrl = if qos_ctrl {
810 Some(
811 wmm::derive_tid(ether_type, payload)
812 .map_or(mac::QosControl(0), |tid| mac::QosControl(0).with_tid(tid as u16)),
813 )
814 } else {
815 None
816 };
817
818 let to_ds = true;
825 let from_ds = src != self.sta.iface_mac;
826 let addr1 = self.sta.bssid().into();
828 let addr2 = self.sta.iface_mac;
829 let addr3 = match (to_ds, from_ds) {
830 (false, false) => self.sta.bssid().into(),
831 (false, true) => src,
832 (true, _) => dst,
833 };
834 let addr4 = if from_ds && to_ds { Some(src) } else { None };
835
836 let tx_flags = match ether_type {
837 mac::ETHER_TYPE_EAPOL => fidl_softmac::WlanTxInfoFlags::FAVOR_RELIABILITY,
838 _ => fidl_softmac::WlanTxInfoFlags::empty(),
839 };
840
841 const MAX_HEADER_SIZE: usize = mem::size_of::<mac::FixedDataHdrFields>()
845 + mem::size_of::<MacAddr>()
846 + mem::size_of::<mac::QosControl>()
847 + mem::size_of::<mac::LlcHdr>();
848 let header_room = MAX_HEADER_SIZE + 100;
849 let arena = Arena::new();
850 let mut buffer = arena.insert_default_slice(header_room + payload.len());
851
852 let payload_start = buffer.len() - payload.len();
855 buffer[payload_start..].clone_from_slice(&payload[..]);
856
857 let (frame_start, _frame_end) =
858 write_frame_with_fixed_slice!(&mut buffer[..payload_start], {
859 fill_zeroes: (),
860 headers: {
861 mac::FixedDataHdrFields: &mac::FixedDataHdrFields {
862 frame_ctrl: mac::FrameControl(0)
863 .with_frame_type(mac::FrameType::DATA)
864 .with_data_subtype(mac::DataSubtype(0).with_qos(qos_ctrl.is_some()))
865 .with_protected(is_protected)
866 .with_to_ds(to_ds)
867 .with_from_ds(from_ds),
868 duration: 0,
869 addr1,
870 addr2,
871 addr3,
872 seq_ctrl: mac::SequenceControl(0).with_seq_num(
873 match qos_ctrl.as_ref() {
874 None => self.ctx.seq_mgr.next_sns1(&dst),
875 Some(qos_ctrl) => self.ctx.seq_mgr.next_sns2(&dst, qos_ctrl.tid()),
876 } as u16
877 )
878 },
879 mac::Addr4?: addr4,
880 mac::QosControl?: qos_ctrl,
881 mac::LlcHdr: &data_writer::make_snap_llc_hdr(ether_type),
882 },
883 })
884 .map_err(|e| {
885 if !async_id_provided {
886 wtrace::async_end_wlansoftmac_tx(async_id, zx::Status::INTERNAL);
887 }
888 e
889 })?;
890
891 let buffer = unsafe {
895 arena.assume_unchecked(NonNull::new_unchecked(
896 &mut ArenaBox::into_ptr(buffer).as_mut()[frame_start..],
897 ))
898 };
899 let buffer = arena.make_static(buffer);
900 self.ctx.device.send_wlan_frame(buffer, tx_flags, Some(async_id)).map_err(|s| {
901 if !async_id_provided {
902 wtrace::async_end_wlansoftmac_tx(async_id, s);
903 }
904 Error::Status(format!("error sending data frame"), s)
905 })
906 }
907
908 fn send_eapol_indication(
911 &mut self,
912 src_addr: MacAddr,
913 dst_addr: MacAddr,
914 eapol_frame: &[u8],
915 ) -> Result<(), Error> {
916 self.ctx
917 .device
918 .send_mlme_event(fidl_mlme::MlmeEvent::EapolInd {
919 ind: fidl_mlme::EapolIndication {
920 src_addr: src_addr.to_array(),
921 dst_addr: dst_addr.to_array(),
922 data: eapol_frame.to_vec(),
923 },
924 })
925 .map_err(|e| e.into())
926 }
927
928 pub fn send_eapol_frame(
931 &mut self,
932 src: MacAddr,
933 dst: MacAddr,
934 is_protected: bool,
935 eapol_frame: &[u8],
936 ) {
937 let result = self.send_data_frame(
940 src,
941 dst,
942 is_protected,
943 false, mac::ETHER_TYPE_EAPOL,
945 eapol_frame,
946 None,
947 );
948 let result_code = match result {
949 Ok(()) => fidl_mlme::EapolResultCode::Success,
950 Err(e) => {
951 error!("error sending EAPoL frame: {}", e);
952 fidl_mlme::EapolResultCode::TransmissionFailure
953 }
954 };
955
956 self.ctx
958 .device
959 .send_mlme_event(fidl_mlme::MlmeEvent::EapolConf {
960 resp: fidl_mlme::EapolConfirm { result_code, dst_addr: dst.to_array() },
961 })
962 .unwrap_or_else(|e| error!("error sending MLME-EAPOL.confirm message: {}", e));
963 }
964
965 pub fn send_ps_poll_frame(&mut self, aid: Aid) -> Result<(), Error> {
966 const PS_POLL_ID_MASK: u16 = 0b11000000_00000000;
967
968 let buffer = write_frame!({
969 headers: {
970 mac::FrameControl: &mac::FrameControl(0)
971 .with_frame_type(mac::FrameType::CTRL)
972 .with_ctrl_subtype(mac::CtrlSubtype::PS_POLL),
973 mac::PsPoll: &mac::PsPoll {
974 masked_aid: aid | PS_POLL_ID_MASK,
977 bssid: self.sta.bssid(),
978 ta: self.sta.iface_mac,
979 },
980 },
981 })?;
982 self.send_mgmt_or_ctrl_frame(buffer)
983 .map_err(|s| Error::Status(format!("error sending PS-Poll frame"), s))
984 }
985
986 pub async fn handle_timed_event(&mut self, event: TimedEvent) {
988 self.sta.state = Some(self.sta.state.take().unwrap().on_timed_event(self, event).await)
989 }
990
991 pub async fn on_mac_frame<B: SplitByteSlice>(
993 &mut self,
994 bytes: B,
995 rx_info: fidl_softmac::WlanRxInfo,
996 async_id: trace::Id,
997 ) {
998 wtrace::duration!(c"BoundClient::on_mac_frame");
999 self.sta.state =
1001 Some(self.sta.state.take().unwrap().on_mac_frame(self, bytes, rx_info, async_id).await);
1002 }
1003
1004 pub fn on_eth_frame_tx<B: SplitByteSlice>(
1005 &mut self,
1006 frame: B,
1007 async_id: trace::Id,
1008 ) -> Result<(), Error> {
1009 wtrace::duration!(c"BoundClient::on_eth_frame_tx");
1010 let state = self.sta.state.take().unwrap();
1012 let result = state.on_eth_frame(self, frame, async_id);
1013 self.sta.state.replace(state);
1014 result
1015 }
1016
1017 pub async fn start_connecting(&mut self) {
1018 let next_state = self.sta.state.take().unwrap().start_connecting(self).await;
1020 self.sta.state.replace(next_state);
1021 }
1022
1023 pub async fn handle_mlme_req(&mut self, msg: wlan_sme::MlmeRequest) {
1024 let next_state = self.sta.state.take().unwrap().handle_mlme_req(self, msg).await;
1026 self.sta.state.replace(next_state);
1027 }
1028
1029 fn send_connect_conf_failure(&mut self, result_code: fidl_ieee80211::StatusCode) {
1030 self.sta.connect_timeout.take();
1031 let bssid = self.sta.connect_req.selected_bss.bssid;
1032 self.send_connect_conf_failure_with_bssid(bssid, result_code);
1033 }
1034
1035 fn send_connect_conf_failure_with_bssid(
1038 &mut self,
1039 bssid: Bssid,
1040 result_code: fidl_ieee80211::StatusCode,
1041 ) {
1042 let connect_conf = fidl_mlme::ConnectConfirm {
1043 peer_sta_address: bssid.to_array(),
1044 result_code,
1045 association_id: 0,
1046 association_ies: vec![],
1047 };
1048 self.ctx
1049 .device
1050 .send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf { resp: connect_conf })
1051 .unwrap_or_else(|e| error!("error sending MLME-CONNECT.confirm: {}", e));
1052 }
1053
1054 fn send_connect_conf_success<B: SplitByteSlice>(
1055 &mut self,
1056 association_id: mac::Aid,
1057 association_ies: B,
1058 ) {
1059 self.sta.connect_timeout.take();
1060 let connect_conf = fidl_mlme::ConnectConfirm {
1061 peer_sta_address: self.sta.connect_req.selected_bss.bssid.to_array(),
1062 result_code: fidl_ieee80211::StatusCode::Success,
1063 association_id,
1064 association_ies: association_ies.to_vec(),
1065 };
1066 self.ctx
1067 .device
1068 .send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf { resp: connect_conf })
1069 .unwrap_or_else(|e| error!("error sending MLME-CONNECT.confirm: {}", e));
1070 }
1071
1072 fn send_deauthenticate_ind(
1074 &mut self,
1075 reason_code: fidl_ieee80211::ReasonCode,
1076 locally_initiated: LocallyInitiated,
1077 ) {
1078 self.channel_state.bind(&mut self.ctx, &mut self.scanner).clear_main_channel();
1080
1081 self.ctx
1082 .device
1083 .send_mlme_event(fidl_mlme::MlmeEvent::DeauthenticateInd {
1084 ind: fidl_mlme::DeauthenticateIndication {
1085 peer_sta_address: self.sta.bssid().to_array(),
1086 reason_code,
1087 locally_initiated: locally_initiated.0,
1088 },
1089 })
1090 .unwrap_or_else(|e| error!("error sending MLME-DEAUTHENTICATE.indication: {}", e));
1091 }
1092
1093 fn send_disassoc_ind(
1095 &mut self,
1096 reason_code: fidl_ieee80211::ReasonCode,
1097 locally_initiated: LocallyInitiated,
1098 ) {
1099 self.ctx
1100 .device
1101 .send_mlme_event(fidl_mlme::MlmeEvent::DisassociateInd {
1102 ind: fidl_mlme::DisassociateIndication {
1103 peer_sta_address: self.sta.bssid().to_array(),
1104 reason_code,
1105 locally_initiated: locally_initiated.0,
1106 },
1107 })
1108 .unwrap_or_else(|e| error!("error sending MLME-DISASSOCIATE.indication: {}", e));
1109 }
1110
1111 async fn clear_association(&mut self) -> Result<(), zx::Status> {
1112 self.ctx
1113 .device
1114 .clear_association(&fidl_softmac::WlanSoftmacBaseClearAssociationRequest {
1115 peer_addr: Some(self.sta.bssid().to_array()),
1116 ..Default::default()
1117 })
1118 .await
1119 }
1120
1121 fn forward_sae_frame_rx(
1123 &mut self,
1124 seq_num: u16,
1125 status_code: fidl_ieee80211::StatusCode,
1126 sae_fields: Vec<u8>,
1127 ) {
1128 self.ctx
1129 .device
1130 .send_mlme_event(fidl_mlme::MlmeEvent::OnSaeFrameRx {
1131 frame: fidl_mlme::SaeFrame {
1132 peer_sta_address: self.sta.bssid().to_array(),
1133 seq_num,
1134 status_code,
1135 sae_fields,
1136 },
1137 })
1138 .unwrap_or_else(|e| error!("error sending OnSaeFrameRx: {}", e));
1139 }
1140
1141 fn forward_sae_handshake_ind(&mut self) {
1142 self.ctx
1143 .device
1144 .send_mlme_event(fidl_mlme::MlmeEvent::OnSaeHandshakeInd {
1145 ind: fidl_mlme::SaeHandshakeIndication {
1146 peer_sta_address: self.sta.bssid().to_array(),
1147 },
1148 })
1149 .unwrap_or_else(|e| error!("error sending OnSaeHandshakeInd: {}", e));
1150 }
1151
1152 fn send_mgmt_or_ctrl_frame(&mut self, buffer: ArenaStaticBox<[u8]>) -> Result<(), zx::Status> {
1153 self.ctx.device.send_wlan_frame(buffer, fidl_softmac::WlanTxInfoFlags::empty(), None)
1154 }
1155}
1156
1157pub struct ParsedConnectRequest {
1158 pub selected_bss: BssDescription,
1159 pub connect_failure_timeout: u32,
1160 pub auth_type: fidl_mlme::AuthenticationTypes,
1161 pub sae_password: Vec<u8>,
1162 pub wep_key: Option<fidl_mlme::SetKeyDescriptor>,
1163 pub security_ie: Vec<u8>,
1164}
1165
1166pub struct ParsedAssociateResp {
1167 pub association_id: u16,
1168 pub capabilities: CapabilityInfo,
1169 pub rates: Vec<ie::SupportedRate>,
1170 pub ht_cap: Option<ie::HtCapabilities>,
1171 pub vht_cap: Option<ie::VhtCapabilities>,
1172}
1173
1174impl ParsedAssociateResp {
1175 pub fn parse<B: SplitByteSlice>(assoc_resp_frame: &mac::AssocRespFrame<B>) -> Self {
1176 let mut parsed = ParsedAssociateResp {
1177 association_id: assoc_resp_frame.assoc_resp_hdr.aid,
1178 capabilities: assoc_resp_frame.assoc_resp_hdr.capabilities,
1179 rates: vec![],
1180 ht_cap: None,
1181 vht_cap: None,
1182 };
1183 for (id, body) in assoc_resp_frame.ies() {
1184 match id {
1185 Id::SUPPORTED_RATES => match ie::parse_supported_rates(body) {
1186 Err(e) => warn!("invalid Supported Rates: {}", e),
1187 Ok(supported_rates) => {
1188 parsed.rates.extend(supported_rates.iter());
1190 }
1191 },
1192 Id::EXTENDED_SUPPORTED_RATES => match ie::parse_extended_supported_rates(body) {
1193 Err(e) => warn!("invalid Extended Supported Rates: {}", e),
1194 Ok(supported_rates) => {
1195 parsed.rates.extend(supported_rates.iter());
1197 }
1198 },
1199 Id::HT_CAPABILITIES => match ie::parse_ht_capabilities(body) {
1200 Err(e) => warn!("invalid HT Capabilities: {}", e),
1201 Ok(ht_cap) => {
1202 parsed.ht_cap = Some(*ht_cap);
1203 }
1204 },
1205 Id::VHT_CAPABILITIES => match ie::parse_vht_capabilities(body) {
1206 Err(e) => warn!("invalid VHT Capabilities: {}", e),
1207 Ok(vht_cap) => {
1208 parsed.vht_cap = Some(*vht_cap);
1209 }
1210 },
1211 _ => {}
1213 }
1214 }
1215 parsed
1216 }
1217}
1218
1219impl<'a, D: DeviceOps> BlockAckTx for BoundClient<'a, D> {
1220 fn send_block_ack_frame(&mut self, n: usize, body: &[u8]) -> Result<(), Error> {
1224 let arena = Arena::new();
1225 let buffer = arena.insert_default_slice::<u8>(n);
1226 let mut buffer = arena.make_static(buffer);
1227 let mut writer = BufferWriter::new(&mut buffer[..]);
1228 write_block_ack_hdr(
1229 &mut writer,
1230 self.sta.bssid(),
1231 self.sta.iface_mac,
1232 &mut self.ctx.seq_mgr,
1233 )
1234 .and_then(|_| writer.append_bytes(body).map_err(Into::into))?;
1235 self.send_mgmt_or_ctrl_frame(buffer)
1236 .map_err(|status| Error::Status(format!("error sending BlockAck frame"), status))
1237 }
1238}
1239
1240fn write_block_ack_hdr<B: Append>(
1245 buffer: &mut B,
1246 bssid: Bssid,
1247 addr: MacAddr,
1248 seq_mgr: &mut SequenceManager,
1249) -> Result<(), Error> {
1250 Ok(append_frame_to!(
1254 buffer,
1255 {
1256 headers: {
1257 mac::MgmtHdr: &mgmt_writer::mgmt_hdr_to_ap(
1258 mac::FrameControl(0)
1259 .with_frame_type(mac::FrameType::MGMT)
1260 .with_mgmt_subtype(mac::MgmtSubtype::ACTION),
1261 bssid,
1262 addr,
1263 mac::SequenceControl(0)
1264 .with_seq_num(seq_mgr.next_sns1(&bssid.into()) as u16),
1265 ),
1266 },
1267 }
1268 )
1269 .map(|_buffer| {})?)
1270}
1271
1272#[cfg(test)]
1273mod tests {
1274 use super::state::DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT;
1275 use super::*;
1276 use crate::block_ack::{
1277 self, ADDBA_REQ_FRAME_LEN, ADDBA_RESP_FRAME_LEN, BlockAckState, Closed,
1278 };
1279 use crate::client::lost_bss::LostBssCounter;
1280 use crate::client::test_utils::drain_timeouts;
1281 use crate::device::{FakeDevice, FakeDeviceConfig, FakeDeviceState, LinkStatus, test_utils};
1282 use crate::test_utils::{MockWlanRxInfo, fake_wlan_channel};
1283 use assert_matches::assert_matches;
1284 use fuchsia_sync::Mutex;
1285 use std::sync::{Arc, LazyLock};
1286 use wlan_common::capabilities::StaCapabilities;
1287 use wlan_common::channel::Cbw;
1288 use wlan_common::stats::SignalStrengthAverage;
1289 use wlan_common::test_utils::fake_capabilities::fake_client_capabilities;
1290 use wlan_common::test_utils::fake_frames::*;
1291 use wlan_common::timer::{self, create_timer};
1292 use wlan_common::{fake_bss_description, fake_fidl_bss_description};
1293 use wlan_sme::responder::Responder;
1294 use wlan_statemachine::*;
1295 use {fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_internal as fidl_internal};
1296 static BSSID: LazyLock<Bssid> = LazyLock::new(|| [6u8; 6].into());
1297 static IFACE_MAC: LazyLock<MacAddr> = LazyLock::new(|| [7u8; 6].into());
1298 const RSNE: &[u8] = &[
1299 0x30, 0x14, 1, 0, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x02, 0xa8, 0x04, ];
1308 const SCAN_CHANNEL_PRIMARY: u8 = 6;
1309 #[rustfmt::skip]
1311 const BEACON_FRAME: &'static [u8] = &[
1312 0b10000000, 0, 0, 0, 255, 255, 255, 255, 255, 255, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 33, 0, 0, 4, 0x73, 0x73, 0x69, 0x64, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 3, 1, 11, 5, 4, 0, 0, 0, 0, ];
1329
1330 struct MockObjects {
1331 fake_device: FakeDevice,
1332 fake_device_state: Arc<Mutex<FakeDeviceState>>,
1333 timer: Option<Timer<super::TimedEvent>>,
1334 time_stream: timer::EventStream<super::TimedEvent>,
1335 }
1336
1337 impl MockObjects {
1338 async fn new() -> Self {
1342 let (timer, time_stream) = create_timer();
1343 let (fake_device, fake_device_state) = FakeDevice::new_with_config(
1344 FakeDeviceConfig::default()
1345 .with_mock_mac_role(fidl_common::WlanMacRole::Client)
1346 .with_mock_sta_addr((*IFACE_MAC).to_array()),
1347 )
1348 .await;
1349 Self { fake_device, fake_device_state, timer: Some(timer), time_stream }
1350 }
1351
1352 async fn make_mlme(&mut self) -> ClientMlme<FakeDevice> {
1353 let mut mlme = ClientMlme::new(
1354 Default::default(),
1355 self.fake_device.clone(),
1356 self.timer.take().unwrap(),
1357 )
1358 .await
1359 .expect("Failed to create client MLME.");
1360 mlme.set_main_channel(fake_wlan_channel().into())
1361 .await
1362 .expect("unable to set main channel");
1363 mlme
1364 }
1365 }
1366
1367 fn scan_req() -> fidl_mlme::ScanRequest {
1368 fidl_mlme::ScanRequest {
1369 txn_id: 1337,
1370 scan_type: fidl_mlme::ScanTypes::Passive,
1371 channel_list: vec![SCAN_CHANNEL_PRIMARY],
1372 ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
1373 probe_delay: 0,
1374 min_channel_time: 100,
1375 max_channel_time: 300,
1376 }
1377 }
1378
1379 fn make_client_station() -> Client {
1380 let connect_req = ParsedConnectRequest {
1381 selected_bss: fake_bss_description!(Open, bssid: BSSID.to_array()),
1382 connect_failure_timeout: 100,
1383 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1384 sae_password: vec![],
1385 wep_key: None,
1386 security_ie: vec![],
1387 };
1388 Client::new(connect_req, *IFACE_MAC, fake_client_capabilities())
1389 }
1390
1391 fn make_client_station_protected() -> Client {
1392 let connect_req = ParsedConnectRequest {
1393 selected_bss: fake_bss_description!(Wpa2, bssid: BSSID.to_array()),
1394 connect_failure_timeout: 100,
1395 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1396 sae_password: vec![],
1397 wep_key: None,
1398 security_ie: RSNE.to_vec(),
1399 };
1400 Client::new(connect_req, *IFACE_MAC, fake_client_capabilities())
1401 }
1402
1403 impl ClientMlme<FakeDevice> {
1404 fn make_client_station(&mut self) {
1405 self.sta.replace(make_client_station());
1406 }
1407
1408 fn make_client_station_protected(&mut self) {
1409 self.sta.replace(make_client_station_protected());
1410 }
1411
1412 fn get_bound_client(&mut self) -> Option<BoundClient<'_, FakeDevice>> {
1413 match self.sta.as_mut() {
1414 None => None,
1415 Some(sta) => {
1416 Some(sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state))
1417 }
1418 }
1419 }
1420 }
1421
1422 impl BoundClient<'_, FakeDevice> {
1423 fn move_to_associated_state(&mut self) {
1424 use super::state::*;
1425 let status_check_timeout =
1426 schedule_association_status_timeout(self.sta.beacon_period(), &mut self.ctx.timer);
1427 let state =
1428 States::from(wlan_statemachine::testing::new_state(Associated(Association {
1429 aid: 42,
1430 assoc_resp_ies: vec![],
1431 controlled_port_open: true,
1432 ap_ht_op: None,
1433 ap_vht_op: None,
1434 qos: Qos::Disabled,
1435 lost_bss_counter: LostBssCounter::start(
1436 self.sta.beacon_period(),
1437 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
1438 ),
1439 status_check_timeout,
1440 signal_strength_average: SignalStrengthAverage::new(),
1441 block_ack_state: StateMachine::new(BlockAckState::from(State::new(Closed))),
1442 })));
1443 self.sta.state.replace(state);
1444 }
1445
1446 async fn close_controlled_port(&mut self) {
1447 self.handle_mlme_req(wlan_sme::MlmeRequest::SetCtrlPort(
1448 fidl_mlme::SetControlledPortRequest {
1449 peer_sta_address: BSSID.to_array(),
1450 state: fidl_mlme::ControlledPortState::Closed,
1451 },
1452 ))
1453 .await;
1454 }
1455 }
1456
1457 #[fuchsia::test(allow_stalls = false)]
1458 async fn spawns_new_sta_on_connect_request_from_sme() {
1459 let mut m = MockObjects::new().await;
1460 let mut me = m.make_mlme().await;
1461 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1462 me.on_sme_connect(fidl_mlme::ConnectRequest {
1463 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
1464 connect_failure_timeout: 100,
1465 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1466 sae_password: vec![],
1467 wep_key: None,
1468 security_ie: vec![],
1469 })
1470 .await
1471 .expect("valid ConnectRequest should be handled successfully");
1472 me.get_bound_client().expect("client sta should have been created by now.");
1473 }
1474
1475 #[fuchsia::test(allow_stalls = false)]
1476 async fn fails_to_connect_if_channel_unknown() {
1477 let mut m = MockObjects::new().await;
1478 let mut me = m.make_mlme().await;
1479 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1480 let mut req = fidl_mlme::ConnectRequest {
1481 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
1482 connect_failure_timeout: 100,
1483 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1484 sae_password: vec![],
1485 wep_key: None,
1486 security_ie: vec![],
1487 };
1488
1489 req.selected_bss.channel.cbw = fidl_fuchsia_wlan_ieee80211::ChannelBandwidth::unknown();
1490 me.on_sme_connect(req)
1491 .await
1492 .expect_err("ConnectRequest with unknown channel should be rejected");
1493 assert!(me.get_bound_client().is_none());
1494 }
1495
1496 #[fuchsia::test(allow_stalls = false)]
1497 async fn rsn_ie_implies_sta_eapol_required() {
1498 let mut m = MockObjects::new().await;
1499 let mut me = m.make_mlme().await;
1500 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1501 me.on_sme_connect(fidl_mlme::ConnectRequest {
1502 selected_bss: fake_fidl_bss_description!(Wpa2, ssid: Ssid::try_from("foo").unwrap()),
1503 connect_failure_timeout: 100,
1504 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1505 sae_password: vec![],
1506 wep_key: None,
1507 security_ie: vec![],
1508 })
1509 .await
1510 .expect("valid ConnectRequest should be handled successfully");
1511 let client = me.get_bound_client().expect("client sta should have been created by now.");
1512 assert!(client.sta.eapol_required());
1513 }
1514
1515 #[fuchsia::test(allow_stalls = false)]
1516 async fn wpa1_implies_sta_eapol_required() {
1517 let mut m = MockObjects::new().await;
1518 let mut me = m.make_mlme().await;
1519 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1520 me.on_sme_connect(fidl_mlme::ConnectRequest {
1521 selected_bss: fake_fidl_bss_description!(Wpa1, ssid: Ssid::try_from("foo").unwrap()),
1522 connect_failure_timeout: 100,
1523 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1524 sae_password: vec![],
1525 wep_key: None,
1526 security_ie: vec![],
1527 })
1528 .await
1529 .expect("valid ConnectRequest should be handled successfully");
1530 let client = me.get_bound_client().expect("client sta should have been created by now.");
1531 assert!(client.sta.eapol_required());
1532 }
1533
1534 #[fuchsia::test(allow_stalls = false)]
1535 async fn no_wpa_or_rsn_ie_implies_sta_eapol_not_required() {
1536 let mut m = MockObjects::new().await;
1537 let mut me = m.make_mlme().await;
1538 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1539 me.on_sme_connect(fidl_mlme::ConnectRequest {
1540 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
1541 connect_failure_timeout: 100,
1542 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1543 sae_password: vec![],
1544 wep_key: None,
1545 security_ie: vec![],
1546 })
1547 .await
1548 .expect("valid ConnectRequest should be handled successfully");
1549 let client = me.get_bound_client().expect("client sta should have been created by now.");
1550 assert!(!client.sta.eapol_required());
1551 }
1552
1553 async fn handle_association_status_checks_and_signal_reports(
1563 mock_objects: &mut MockObjects,
1564 mlme: &mut ClientMlme<FakeDevice>,
1565 beacon_count: u32,
1566 ) {
1567 for _ in 0..beacon_count / super::state::ASSOCIATION_STATUS_TIMEOUT_BEACON_COUNT {
1568 let (_, timed_event, _) = mock_objects
1569 .time_stream
1570 .try_next()
1571 .unwrap()
1572 .expect("Should have scheduled a timed event");
1573 mlme.handle_timed_event(timed_event.event).await;
1574 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 0);
1575 mock_objects
1576 .fake_device_state
1577 .lock()
1578 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
1579 .expect("error reading SignalReport.indication");
1580 }
1581 }
1582
1583 #[fuchsia::test(allow_stalls = false)]
1584 async fn test_auto_deauth_uninterrupted_interval() {
1585 let mut mock_objects = MockObjects::new().await;
1586 let mut mlme = mock_objects.make_mlme().await;
1587 mlme.make_client_station();
1588 let mut client = mlme.get_bound_client().expect("client should be present");
1589
1590 client.move_to_associated_state();
1591
1592 handle_association_status_checks_and_signal_reports(
1594 &mut mock_objects,
1595 &mut mlme,
1596 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
1597 )
1598 .await;
1599
1600 let (_, timed_event, _) = mock_objects
1602 .time_stream
1603 .try_next()
1604 .unwrap()
1605 .expect("Should have scheduled a timed event");
1606
1607 mlme.handle_timed_event(timed_event.event).await;
1609 mock_objects
1610 .fake_device_state
1611 .lock()
1612 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
1613 .expect("error reading SignalReport.indication");
1614 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
1615 #[rustfmt::skip]
1616 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
1617 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, ][..]);
1626 let deauth_ind = mock_objects
1627 .fake_device_state
1628 .lock()
1629 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
1630 .expect("error reading DEAUTHENTICATE.indication");
1631 assert_eq!(
1632 deauth_ind,
1633 fidl_mlme::DeauthenticateIndication {
1634 peer_sta_address: BSSID.to_array(),
1635 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
1636 locally_initiated: true,
1637 }
1638 );
1639 }
1640
1641 #[fuchsia::test(allow_stalls = false)]
1642 async fn test_auto_deauth_received_beacon() {
1643 let mut mock_objects = MockObjects::new().await;
1644 let mut mlme = mock_objects.make_mlme().await;
1645 mlme.make_client_station();
1646 let mut client = mlme.get_bound_client().expect("client should be present");
1647
1648 client.move_to_associated_state();
1649
1650 handle_association_status_checks_and_signal_reports(
1652 &mut mock_objects,
1653 &mut mlme,
1654 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
1655 )
1656 .await;
1657
1658 mlme.on_mac_frame_rx(
1661 BEACON_FRAME,
1662 fidl_softmac::WlanRxInfo {
1663 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
1664 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
1665 phy: fidl_common::WlanPhyType::Dsss,
1666 data_rate: 0,
1667 channel: mlme.channel_state.get_main_channel().unwrap(),
1668 mcs: 0,
1669 rssi_dbm: 0,
1670 snr_dbh: 0,
1671 },
1672 0.into(),
1673 )
1674 .await;
1675
1676 handle_association_status_checks_and_signal_reports(
1678 &mut mock_objects,
1679 &mut mlme,
1680 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
1681 )
1682 .await;
1683
1684 let (_, timed_event2, _) = mock_objects
1686 .time_stream
1687 .try_next()
1688 .unwrap()
1689 .expect("Should have scheduled a timed event");
1690
1691 mlme.handle_timed_event(timed_event2.event).await;
1693 mock_objects
1694 .fake_device_state
1695 .lock()
1696 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
1697 .expect("error reading SignalReport.indication");
1698 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
1699 #[rustfmt::skip]
1700 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
1701 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, ][..]);
1710 let deauth_ind = mock_objects
1711 .fake_device_state
1712 .lock()
1713 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
1714 .expect("error reading DEAUTHENTICATE.indication");
1715 assert_eq!(
1716 deauth_ind,
1717 fidl_mlme::DeauthenticateIndication {
1718 peer_sta_address: BSSID.to_array(),
1719 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
1720 locally_initiated: true,
1721 }
1722 );
1723 }
1724
1725 #[fuchsia::test(allow_stalls = false)]
1726 async fn client_send_open_auth_frame() {
1727 let mut m = MockObjects::new().await;
1728 let mut me = m.make_mlme().await;
1729 me.make_client_station();
1730 let mut client = me.get_bound_client().expect("client should be present");
1731 client.send_open_auth_frame().expect("error delivering WLAN frame");
1732 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1733 #[rustfmt::skip]
1734 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1735 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, ][..]);
1747 }
1748
1749 #[fuchsia::test(allow_stalls = false)]
1750 async fn client_send_assoc_req_frame() {
1751 let mut m = MockObjects::new().await;
1752 let mut me = m.make_mlme().await;
1753 let connect_req = ParsedConnectRequest {
1754 selected_bss: fake_bss_description!(Wpa2,
1755 ssid: Ssid::try_from([11, 22, 33, 44]).unwrap(),
1756 bssid: BSSID.to_array(),
1757 ),
1758 connect_failure_timeout: 100,
1759 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1760 sae_password: vec![],
1761 wep_key: None,
1762 security_ie: RSNE.to_vec(),
1763 };
1764 let client_capabilities = ClientCapabilities(StaCapabilities {
1765 capability_info: CapabilityInfo(0x1234),
1766 rates: vec![8u8, 7, 6, 5, 4, 3, 2, 1, 0].into_iter().map(ie::SupportedRate).collect(),
1767 ht_cap: ie::parse_ht_capabilities(&(0..26).collect::<Vec<u8>>()[..]).map(|h| *h).ok(),
1768 vht_cap: ie::parse_vht_capabilities(&(100..112).collect::<Vec<u8>>()[..])
1769 .map(|v| *v)
1770 .ok(),
1771 });
1772 me.sta.replace(Client::new(connect_req, *IFACE_MAC, client_capabilities));
1773 let mut client = me.get_bound_client().expect("client should be present");
1774 client.send_assoc_req_frame().expect("error delivering WLAN frame");
1775 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1776 assert_eq!(
1777 &m.fake_device_state.lock().wlan_queue[0].0[..],
1778 &[
1779 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 0x34, 0x12, 0, 0, 0, 4, 11, 22, 33, 44, 1, 8, 8, 7, 6, 5, 4, 3, 2, 1, 50, 1, 0, 0x30, 0x14, 1, 0, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x02, 0xa8, 0x04, 45, 26, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 191, 12, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, ][..]
1813 );
1814 }
1815
1816 #[fuchsia::test(allow_stalls = false)]
1817 async fn client_send_keep_alive_resp_frame() {
1818 let mut m = MockObjects::new().await;
1819 let mut me = m.make_mlme().await;
1820 me.make_client_station();
1821 let mut client = me.get_bound_client().expect("client should be present");
1822 client.send_keep_alive_resp_frame().expect("error delivering WLAN frame");
1823 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1824 #[rustfmt::skip]
1825 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1826 0b0100_10_00, 0b0000000_1, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, ][..]);
1834 }
1835
1836 #[fuchsia::test(allow_stalls = false)]
1837 async fn client_send_data_frame() {
1838 let payload = vec![5; 8];
1839 let mut m = MockObjects::new().await;
1840 let mut me = m.make_mlme().await;
1841 me.make_client_station();
1842 let mut client = me.get_bound_client().expect("client should be present");
1843 client
1844 .send_data_frame(*IFACE_MAC, [4; 6].into(), false, false, 0x1234, &payload[..], None)
1845 .expect("error delivering WLAN frame");
1846 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1847 #[rustfmt::skip]
1848 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1849 0b0000_10_00, 0b0000000_1, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 0x10, 0, 0xAA, 0xAA, 0x03, 0, 0, 0, 0x12, 0x34, 5, 5, 5, 5, 5, 5, 5, 5,
1862 ][..]);
1863 }
1864
1865 #[fuchsia::test(allow_stalls = false)]
1866 async fn client_send_data_frame_ipv4_qos() {
1867 let mut m = MockObjects::new().await;
1868 let mut me = m.make_mlme().await;
1869 let mut client = make_client_station();
1870 client
1871 .bind(&mut me.ctx, &mut me.scanner, &mut me.channel_state)
1872 .send_data_frame(
1873 *IFACE_MAC,
1874 [4; 6].into(),
1875 false,
1876 true,
1877 0x0800, &[1, 0xB0, 3, 4, 5], None,
1880 )
1881 .expect("error delivering WLAN frame");
1882 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1883 #[rustfmt::skip]
1884 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1885 0b1000_10_00, 0b0000000_1, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 0x10, 0, 0x06, 0, 0xAA, 0xAA, 0x03, 0, 0, 0, 0x08, 0x00, 1, 0xB0, 3, 4, 5,
1899 ][..]);
1900 }
1901
1902 #[fuchsia::test(allow_stalls = false)]
1903 async fn client_send_data_frame_ipv6_qos() {
1904 let mut m = MockObjects::new().await;
1905 let mut me = m.make_mlme().await;
1906 let mut client = make_client_station();
1907 client
1908 .bind(&mut me.ctx, &mut me.scanner, &mut me.channel_state)
1909 .send_data_frame(
1910 *IFACE_MAC,
1911 [4; 6].into(),
1912 false,
1913 true,
1914 0x86DD, &[0b0101, 0b10000000, 3, 4, 5], None,
1917 )
1918 .expect("error delivering WLAN frame");
1919 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1920 #[rustfmt::skip]
1921 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1922 0b1000_10_00, 0b0000000_1, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 0x10, 0, 0x03, 0, 0xAA, 0xAA, 0x03, 0, 0, 0, 0x86, 0xDD, 0b0101, 0b10000000, 3, 4, 5,
1936 ][..]);
1937 }
1938
1939 #[fuchsia::test(allow_stalls = false)]
1940 async fn client_send_data_frame_from_ds() {
1941 let payload = vec![5; 8];
1942 let mut m = MockObjects::new().await;
1943 let mut me = m.make_mlme().await;
1944 me.make_client_station();
1945 let mut client = me.get_bound_client().expect("client should be present");
1946 client
1947 .send_data_frame([3; 6].into(), [4; 6].into(), false, false, 0x1234, &payload[..], None)
1948 .expect("error delivering WLAN frame");
1949 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1950 #[rustfmt::skip]
1951 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1952 0b0000_10_00, 0b000000_11, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 0x10, 0, 3, 3, 3, 3, 3, 3, 0xAA, 0xAA, 0x03, 0, 0, 0, 0x12, 0x34, 5, 5, 5, 5, 5, 5, 5, 5,
1966 ][..]);
1967 }
1968
1969 #[fuchsia::test(allow_stalls = false)]
1970 async fn client_send_deauthentication_notification() {
1971 let mut m = MockObjects::new().await;
1972 let mut me = m.make_mlme().await;
1973 me.make_client_station();
1974 let mut client = me.get_bound_client().expect("client should be present");
1975
1976 client
1977 .send_deauth_frame(fidl_ieee80211::ReasonCode::ApInitiated.into())
1978 .expect("error delivering WLAN frame");
1979 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1980 #[rustfmt::skip]
1981 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1982 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, 47, 0, ][..]);
1991 }
1992
1993 fn mock_rx_info<'a>(client: &BoundClient<'a, FakeDevice>) -> fidl_softmac::WlanRxInfo {
1994 let channel = client.channel_state.get_main_channel().unwrap();
1995 MockWlanRxInfo::with_channel(channel).into()
1996 }
1997
1998 #[fuchsia::test(allow_stalls = false)]
1999 async fn respond_to_keep_alive_request() {
2000 #[rustfmt::skip]
2001 let data_frame = vec![
2002 0b0100_10_00, 0b000000_1_0, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 42, 42, 42, 42, 42, 42, 0x10, 0, ];
2010 let mut m = MockObjects::new().await;
2011 let mut me = m.make_mlme().await;
2012 me.make_client_station();
2013 let mut client = me.get_bound_client().expect("client should be present");
2014 client.move_to_associated_state();
2015
2016 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2017
2018 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2019 #[rustfmt::skip]
2020 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
2021 0b0100_10_00, 0b0000000_1, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, ][..]);
2029 }
2030
2031 #[fuchsia::test(allow_stalls = false)]
2032 async fn data_frame_to_ethernet_single_llc() {
2033 let mut data_frame = make_data_frame_single_llc(None, None);
2034 data_frame[1] = 0b00000010; data_frame[4..10].copy_from_slice(IFACE_MAC.as_array()); data_frame[10..16].copy_from_slice(BSSID.as_array()); let mut m = MockObjects::new().await;
2039 let mut me = m.make_mlme().await;
2040 me.make_client_station();
2041 let mut client = me.get_bound_client().expect("client should be present");
2042 client.move_to_associated_state();
2043
2044 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2045
2046 assert_eq!(m.fake_device_state.lock().eth_queue.len(), 1);
2047 #[rustfmt::skip]
2048 assert_eq!(m.fake_device_state.lock().eth_queue[0], [
2049 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 9, 10, 11, 11, 11, ]);
2054 }
2055
2056 #[fuchsia::test(allow_stalls = false)]
2057 async fn data_frame_to_ethernet_amsdu() {
2058 let mut data_frame = make_data_frame_amsdu();
2059 data_frame[1] = 0b00000010; data_frame[4..10].copy_from_slice(IFACE_MAC.as_array()); data_frame[10..16].copy_from_slice(BSSID.as_array()); let mut m = MockObjects::new().await;
2064 let mut me = m.make_mlme().await;
2065 me.make_client_station();
2066 let mut client = me.get_bound_client().expect("client should be present");
2067 client.move_to_associated_state();
2068
2069 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2070
2071 let queue = &m.fake_device_state.lock().eth_queue;
2072 assert_eq!(queue.len(), 2);
2073 #[rustfmt::skip]
2074 let mut expected_first_eth_frame = vec![
2075 0x78, 0x8a, 0x20, 0x0d, 0x67, 0x03, 0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xab, 0x08, 0x00, ];
2079 expected_first_eth_frame.extend_from_slice(MSDU_1_PAYLOAD);
2080 assert_eq!(queue[0], &expected_first_eth_frame[..]);
2081 #[rustfmt::skip]
2082 let mut expected_second_eth_frame = vec![
2083 0x78, 0x8a, 0x20, 0x0d, 0x67, 0x04, 0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xac, 0x08, 0x01, ];
2087 expected_second_eth_frame.extend_from_slice(MSDU_2_PAYLOAD);
2088 assert_eq!(queue[1], &expected_second_eth_frame[..]);
2089 }
2090
2091 #[fuchsia::test(allow_stalls = false)]
2092 async fn data_frame_to_ethernet_amsdu_padding_too_short() {
2093 let mut data_frame = make_data_frame_amsdu_padding_too_short();
2094 data_frame[1] = 0b00000010; data_frame[4..10].copy_from_slice(IFACE_MAC.as_array()); data_frame[10..16].copy_from_slice(BSSID.as_array()); let mut m = MockObjects::new().await;
2099 let mut me = m.make_mlme().await;
2100 me.make_client_station();
2101 let mut client = me.get_bound_client().expect("client should be present");
2102 client.move_to_associated_state();
2103
2104 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2105
2106 let queue = &m.fake_device_state.lock().eth_queue;
2107 assert_eq!(queue.len(), 1);
2108 #[rustfmt::skip]
2109 let mut expected_first_eth_frame = vec![
2110 0x78, 0x8a, 0x20, 0x0d, 0x67, 0x03, 0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xab, 0x08, 0x00, ];
2114 expected_first_eth_frame.extend_from_slice(MSDU_1_PAYLOAD);
2115 assert_eq!(queue[0], &expected_first_eth_frame[..]);
2116 }
2117
2118 #[fuchsia::test(allow_stalls = false)]
2119 async fn data_frame_controlled_port_closed() {
2120 let mut data_frame = make_data_frame_single_llc(None, None);
2121 data_frame[1] = 0b00000010; data_frame[4..10].copy_from_slice(IFACE_MAC.as_array()); data_frame[10..16].copy_from_slice(BSSID.as_array()); let mut m = MockObjects::new().await;
2126 let mut me = m.make_mlme().await;
2127 me.make_client_station_protected();
2128 let mut client = me.get_bound_client().expect("client should be present");
2129 client.move_to_associated_state();
2130 client.close_controlled_port().await;
2131
2132 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2133
2134 assert_eq!(m.fake_device_state.lock().eth_queue.len(), 0);
2136 }
2137
2138 #[fuchsia::test(allow_stalls = false)]
2139 async fn eapol_frame_controlled_port_closed() {
2140 let (src_addr, dst_addr, mut eapol_frame) = make_eapol_frame(*IFACE_MAC);
2141 eapol_frame[1] = 0b00000010; eapol_frame[4..10].copy_from_slice(IFACE_MAC.as_array()); eapol_frame[10..16].copy_from_slice(BSSID.as_array()); let mut m = MockObjects::new().await;
2146 let mut me = m.make_mlme().await;
2147 me.make_client_station_protected();
2148 let mut client = me.get_bound_client().expect("client should be present");
2149 client.move_to_associated_state();
2150 client.close_controlled_port().await;
2151
2152 client.on_mac_frame(&eapol_frame[..], mock_rx_info(&client), 0.into()).await;
2153
2154 assert_eq!(m.fake_device_state.lock().eth_queue.len(), 0);
2156
2157 let eapol_ind = m
2159 .fake_device_state
2160 .lock()
2161 .next_mlme_msg::<fidl_mlme::EapolIndication>()
2162 .expect("error reading EAPOL.indication");
2163 assert_eq!(
2164 eapol_ind,
2165 fidl_mlme::EapolIndication {
2166 src_addr: src_addr.to_array(),
2167 dst_addr: dst_addr.to_array(),
2168 data: EAPOL_PDU.to_vec()
2169 }
2170 );
2171 }
2172
2173 #[fuchsia::test(allow_stalls = false)]
2174 async fn eapol_frame_is_controlled_port_open() {
2175 let (src_addr, dst_addr, mut eapol_frame) = make_eapol_frame(*IFACE_MAC);
2176 eapol_frame[1] = 0b00000010; eapol_frame[4..10].copy_from_slice(IFACE_MAC.as_array()); eapol_frame[10..16].copy_from_slice(BSSID.as_array()); let mut m = MockObjects::new().await;
2181 let mut me = m.make_mlme().await;
2182 me.make_client_station();
2183 let mut client = me.get_bound_client().expect("client should be present");
2184 client.move_to_associated_state();
2185
2186 client.on_mac_frame(&eapol_frame[..], mock_rx_info(&client), 0.into()).await;
2187
2188 assert_eq!(m.fake_device_state.lock().eth_queue.len(), 0);
2190
2191 let eapol_ind = m
2193 .fake_device_state
2194 .lock()
2195 .next_mlme_msg::<fidl_mlme::EapolIndication>()
2196 .expect("error reading EAPOL.indication");
2197 assert_eq!(
2198 eapol_ind,
2199 fidl_mlme::EapolIndication {
2200 src_addr: src_addr.to_array(),
2201 dst_addr: dst_addr.to_array(),
2202 data: EAPOL_PDU.to_vec()
2203 }
2204 );
2205 }
2206
2207 #[fuchsia::test(allow_stalls = false)]
2208 async fn send_eapol_ind_success() {
2209 let mut m = MockObjects::new().await;
2210 let mut me = m.make_mlme().await;
2211 me.make_client_station();
2212 let mut client = me.get_bound_client().expect("client should be present");
2213 client
2214 .send_eapol_indication([1; 6].into(), [2; 6].into(), &[5; 200])
2215 .expect("expected EAPOL.indication to be sent");
2216 let eapol_ind = m
2217 .fake_device_state
2218 .lock()
2219 .next_mlme_msg::<fidl_mlme::EapolIndication>()
2220 .expect("error reading EAPOL.indication");
2221 assert_eq!(
2222 eapol_ind,
2223 fidl_mlme::EapolIndication {
2224 src_addr: [1; 6].into(),
2225 dst_addr: [2; 6].into(),
2226 data: vec![5; 200]
2227 }
2228 );
2229 }
2230
2231 #[fuchsia::test(allow_stalls = false)]
2232 async fn send_eapol_frame_success() {
2233 let mut m = MockObjects::new().await;
2234 let mut me = m.make_mlme().await;
2235 me.make_client_station();
2236 let mut client = me.get_bound_client().expect("client should be present");
2237 client.send_eapol_frame(*IFACE_MAC, (*BSSID).into(), false, &[5; 8]);
2238
2239 let eapol_confirm = m
2241 .fake_device_state
2242 .lock()
2243 .next_mlme_msg::<fidl_mlme::EapolConfirm>()
2244 .expect("error reading EAPOL.confirm");
2245 assert_eq!(
2246 eapol_confirm,
2247 fidl_mlme::EapolConfirm {
2248 result_code: fidl_mlme::EapolResultCode::Success,
2249 dst_addr: BSSID.to_array(),
2250 }
2251 );
2252
2253 #[rustfmt::skip]
2255 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
2256 0b0000_10_00, 0b0000000_1, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8E, 5, 5, 5, 5, 5, 5, 5, 5,
2269 ][..]);
2270 }
2271
2272 #[fuchsia::test(allow_stalls = false)]
2273 async fn send_eapol_frame_failure() {
2274 let mut m = MockObjects::new().await;
2275 m.fake_device_state.lock().config.send_wlan_frame_fails = true;
2276 let mut me = m.make_mlme().await;
2277 me.make_client_station();
2278 let mut client = me.get_bound_client().expect("client should be present");
2279 client.send_eapol_frame([1; 6].into(), [2; 6].into(), false, &[5; 200]);
2280
2281 let eapol_confirm = m
2283 .fake_device_state
2284 .lock()
2285 .next_mlme_msg::<fidl_mlme::EapolConfirm>()
2286 .expect("error reading EAPOL.confirm");
2287 assert_eq!(
2288 eapol_confirm,
2289 fidl_mlme::EapolConfirm {
2290 result_code: fidl_mlme::EapolResultCode::TransmissionFailure,
2291 dst_addr: [2; 6].into(),
2292 }
2293 );
2294
2295 assert!(m.fake_device_state.lock().wlan_queue.is_empty());
2297 }
2298
2299 #[fuchsia::test(allow_stalls = false)]
2300 async fn send_keys() {
2301 let mut m = MockObjects::new().await;
2302 let mut me = m.make_mlme().await;
2303 me.make_client_station_protected();
2304 let mut client = me.get_bound_client().expect("client should be present");
2305 client.move_to_associated_state();
2306
2307 assert!(m.fake_device_state.lock().keys.is_empty());
2308 client.handle_mlme_req(crate::test_utils::fake_set_keys_req((*BSSID).into())).await;
2309 assert_eq!(m.fake_device_state.lock().keys.len(), 1);
2310
2311 let sent_key = crate::test_utils::fake_key((*BSSID).into());
2312 let received_key = &m.fake_device_state.lock().keys[0];
2313 assert_eq!(received_key.key, Some(sent_key.key));
2314 assert_eq!(received_key.key_idx, Some(sent_key.key_id as u8));
2315 assert_eq!(received_key.key_type, Some(fidl_ieee80211::KeyType::Pairwise));
2316 }
2317
2318 #[fuchsia::test(allow_stalls = false)]
2319 async fn send_addba_req_frame() {
2320 let mut mock = MockObjects::new().await;
2321 let mut mlme = mock.make_mlme().await;
2322 mlme.make_client_station();
2323 let mut client = mlme.get_bound_client().expect("client should be present");
2324
2325 let mut body = [0u8; 16];
2326 let mut writer = BufferWriter::new(&mut body[..]);
2327 block_ack::write_addba_req_body(&mut writer, 1).expect("failed writing addba frame");
2328 client
2329 .send_block_ack_frame(ADDBA_REQ_FRAME_LEN, writer.into_written())
2330 .expect("failed sending addba frame");
2331 assert_eq!(
2332 &mock.fake_device_state.lock().wlan_queue[0].0[..],
2333 &[
2334 0b11010000, 0b00000000, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 0x03, 0x00, 1, 0b00000011, 0b00010000, 0, 0, 0b00010000, 0, ][..]
2349 );
2350 }
2351
2352 #[fuchsia::test(allow_stalls = false)]
2353 async fn send_addba_resp_frame() {
2354 let mut mock = MockObjects::new().await;
2355 let mut mlme = mock.make_mlme().await;
2356 mlme.make_client_station();
2357 let mut client = mlme.get_bound_client().expect("client should be present");
2358
2359 let mut body = [0u8; 16];
2360 let mut writer = BufferWriter::new(&mut body[..]);
2361 block_ack::write_addba_resp_body(&mut writer, 1).expect("failed writing addba frame");
2362 client
2363 .send_block_ack_frame(ADDBA_RESP_FRAME_LEN, writer.into_written())
2364 .expect("failed sending addba frame");
2365 assert_eq!(
2366 &mock.fake_device_state.lock().wlan_queue[0].0[..],
2367 &[
2368 0b11010000, 0b00000000, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 0x03, 0x01, 1, 0, 0, 0b00000011, 0b00010000, 0, 0, ][..]
2383 );
2384 }
2385
2386 #[fuchsia::test(allow_stalls = false)]
2387 async fn client_send_successful_connect_conf() {
2388 let mut m = MockObjects::new().await;
2389 let mut me = m.make_mlme().await;
2390 me.make_client_station();
2391 let mut client = me.get_bound_client().expect("client should be present");
2392
2393 client.send_connect_conf_success(42, &[0, 5, 3, 4, 5, 6, 7][..]);
2394 let connect_conf = m
2395 .fake_device_state
2396 .lock()
2397 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
2398 .expect("error reading Connect.confirm");
2399 assert_eq!(
2400 connect_conf,
2401 fidl_mlme::ConnectConfirm {
2402 peer_sta_address: BSSID.to_array(),
2403 result_code: fidl_ieee80211::StatusCode::Success,
2404 association_id: 42,
2405 association_ies: vec![0, 5, 3, 4, 5, 6, 7],
2406 }
2407 );
2408 }
2409
2410 #[fuchsia::test(allow_stalls = false)]
2411 async fn client_send_failed_connect_conf() {
2412 let mut m = MockObjects::new().await;
2413 let mut me = m.make_mlme().await;
2414 me.make_client_station();
2415 let mut client = me.get_bound_client().expect("client should be present");
2416 client.send_connect_conf_failure(fidl_ieee80211::StatusCode::DeniedNoMoreStas);
2417 let connect_conf = m
2418 .fake_device_state
2419 .lock()
2420 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
2421 .expect("error reading Connect.confirm");
2422 assert_eq!(
2423 connect_conf,
2424 fidl_mlme::ConnectConfirm {
2425 peer_sta_address: BSSID.to_array(),
2426 result_code: fidl_ieee80211::StatusCode::DeniedNoMoreStas,
2427 association_id: 0,
2428 association_ies: vec![],
2429 }
2430 );
2431 }
2432
2433 #[fuchsia::test(allow_stalls = false)]
2434 async fn client_send_scan_end_on_mlme_scan_busy() {
2435 let mut m = MockObjects::new().await;
2436 let mut me = m.make_mlme().await;
2437 me.make_client_station();
2438
2439 me.on_sme_scan(scan_req()).await;
2441 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
2442
2443 let scan_end = m
2444 .fake_device_state
2445 .lock()
2446 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2447 .expect("error reading MLME ScanEnd");
2448 assert_eq!(
2449 scan_end,
2450 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
2451 );
2452 }
2453
2454 #[fuchsia::test(allow_stalls = false)]
2455 async fn client_send_scan_end_on_scan_busy() {
2456 let mut m = MockObjects::new().await;
2457 let mut me = m.make_mlme().await;
2458 me.make_client_station();
2459
2460 me.on_sme_scan(scan_req()).await;
2462 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
2463
2464 let scan_end = m
2465 .fake_device_state
2466 .lock()
2467 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2468 .expect("error reading MLME ScanEnd");
2469 assert_eq!(
2470 scan_end,
2471 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
2472 );
2473 }
2474
2475 #[fuchsia::test(allow_stalls = false)]
2476 async fn client_send_scan_end_on_mlme_scan_invalid_args() {
2477 let mut m = MockObjects::new().await;
2478 let mut me = m.make_mlme().await;
2479
2480 me.make_client_station();
2481 me.on_sme_scan(fidl_mlme::ScanRequest {
2482 txn_id: 1337,
2483 scan_type: fidl_mlme::ScanTypes::Passive,
2484 channel_list: vec![], ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
2486 probe_delay: 0,
2487 min_channel_time: 100,
2488 max_channel_time: 300,
2489 })
2490 .await;
2491 let scan_end = m
2492 .fake_device_state
2493 .lock()
2494 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2495 .expect("error reading MLME ScanEnd");
2496 assert_eq!(
2497 scan_end,
2498 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
2499 );
2500 }
2501
2502 #[fuchsia::test(allow_stalls = false)]
2503 async fn client_send_scan_end_on_scan_invalid_args() {
2504 let mut m = MockObjects::new().await;
2505 let mut me = m.make_mlme().await;
2506
2507 me.make_client_station();
2508 me.on_sme_scan(fidl_mlme::ScanRequest {
2509 txn_id: 1337,
2510 scan_type: fidl_mlme::ScanTypes::Passive,
2511 channel_list: vec![6],
2512 ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
2513 probe_delay: 0,
2514 min_channel_time: 300, max_channel_time: 100,
2516 })
2517 .await;
2518 let scan_end = m
2519 .fake_device_state
2520 .lock()
2521 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2522 .expect("error reading MLME ScanEnd");
2523 assert_eq!(
2524 scan_end,
2525 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
2526 );
2527 }
2528
2529 #[fuchsia::test(allow_stalls = false)]
2530 async fn client_send_scan_end_on_passive_scan_fails() {
2531 let mut m = MockObjects::new().await;
2532 m.fake_device_state.lock().config.start_passive_scan_fails = true;
2533 let mut me = m.make_mlme().await;
2534
2535 me.make_client_station();
2536 me.on_sme_scan(scan_req()).await;
2537 let scan_end = m
2538 .fake_device_state
2539 .lock()
2540 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2541 .expect("error reading MLME ScanEnd");
2542 assert_eq!(
2543 scan_end,
2544 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::NotSupported }
2545 );
2546 }
2547
2548 #[fuchsia::test(allow_stalls = false)]
2549 async fn mlme_respond_to_query_device_info() {
2550 let mut mock_objects = MockObjects::new().await;
2551 let mut mlme = mock_objects.make_mlme().await;
2552
2553 let (responder, receiver) = Responder::new();
2554 mlme.handle_mlme_req(wlan_sme::MlmeRequest::QueryDeviceInfo(responder))
2555 .await
2556 .expect("Failed to send MlmeRequest::Connect");
2557 assert_eq!(
2558 receiver.await.unwrap(),
2559 fidl_mlme::DeviceInfo {
2560 sta_addr: IFACE_MAC.to_array(),
2561 role: fidl_common::WlanMacRole::Client,
2562 bands: test_utils::fake_mlme_band_caps(),
2563 softmac_hardware_capability: 0,
2564 qos_capable: false,
2565 }
2566 );
2567 }
2568
2569 #[fuchsia::test(allow_stalls = false)]
2570 async fn mlme_respond_to_query_mac_sublayer_support() {
2571 let mut m = MockObjects::new().await;
2572 let mut me = m.make_mlme().await;
2573
2574 let (responder, receiver) = Responder::new();
2575 me.handle_mlme_req(wlan_sme::MlmeRequest::QueryMacSublayerSupport(responder))
2576 .await
2577 .expect("Failed to send MlmeRequest::Connect");
2578 let resp = receiver.await.unwrap();
2579 assert_eq!(resp.rate_selection_offload.supported, false);
2580 assert_eq!(resp.data_plane.data_plane_type, fidl_common::DataPlaneType::EthernetDevice);
2581 assert_eq!(resp.device.is_synthetic, true);
2582 assert_eq!(
2583 resp.device.mac_implementation_type,
2584 fidl_common::MacImplementationType::Softmac
2585 );
2586 assert_eq!(resp.device.tx_status_report_supported, true);
2587 }
2588
2589 #[fuchsia::test(allow_stalls = false)]
2590 async fn mlme_respond_to_query_security_support() {
2591 let mut m = MockObjects::new().await;
2592 let mut me = m.make_mlme().await;
2593
2594 let (responder, receiver) = Responder::new();
2595 assert_matches!(
2596 me.handle_mlme_req(wlan_sme::MlmeRequest::QuerySecuritySupport(responder)).await,
2597 Ok(())
2598 );
2599 let resp = receiver.await.unwrap();
2600 assert_eq!(resp.mfp.supported, false);
2601 assert_eq!(resp.sae.driver_handler_supported, false);
2602 assert_eq!(resp.sae.sme_handler_supported, false);
2603 }
2604
2605 #[fuchsia::test(allow_stalls = false)]
2606 async fn mlme_respond_to_query_spectrum_management_support() {
2607 let mut m = MockObjects::new().await;
2608 let mut me = m.make_mlme().await;
2609
2610 let (responder, receiver) = Responder::new();
2611 me.handle_mlme_req(wlan_sme::MlmeRequest::QuerySpectrumManagementSupport(responder))
2612 .await
2613 .expect("Failed to send MlmeRequest::QuerySpectrumManagementSupport");
2614 assert_eq!(receiver.await.unwrap().dfs.supported, true);
2615 }
2616
2617 #[fuchsia::test(allow_stalls = false)]
2618 async fn mlme_connect_unprotected_happy_path() {
2619 let mut m = MockObjects::new().await;
2620 let mut me = m.make_mlme().await;
2621 let channel = Channel::new(6, Cbw::Cbw40);
2622 let connect_req = fidl_mlme::ConnectRequest {
2623 selected_bss: fake_fidl_bss_description!(Open,
2624 ssid: Ssid::try_from("ssid").unwrap().into(),
2625 bssid: BSSID.to_array(),
2626 channel: channel.clone(),
2627 ),
2628 connect_failure_timeout: 100,
2629 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
2630 sae_password: vec![],
2631 wep_key: None,
2632 security_ie: vec![],
2633 };
2634 me.handle_mlme_req(wlan_sme::MlmeRequest::Connect(connect_req))
2635 .await
2636 .expect("Failed to send MlmeRequest::Connect");
2637
2638 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
2640 assert_eq!(ids.len(), 1);
2641 });
2642
2643 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2645 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2646 #[rustfmt::skip]
2647 let expected = vec![
2648 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, ];
2660 assert_eq!(&frame[..], &expected[..]);
2661
2662 #[rustfmt::skip]
2664 let auth_resp_success = vec![
2665 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, ];
2677 me.on_mac_frame_rx(
2678 &auth_resp_success[..],
2679 MockWlanRxInfo::with_channel(channel.into()).into(),
2680 0.into(),
2681 )
2682 .await;
2683
2684 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2686 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2687 #[rustfmt::skip]
2688 let expected = vec![
2689 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, ];
2711 assert_eq!(&frame[..], &expected[..]);
2712
2713 #[rustfmt::skip]
2715 let assoc_resp_success = vec![
2716 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,
2730 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2734 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ];
2738 me.on_mac_frame_rx(
2739 &assoc_resp_success[..],
2740 MockWlanRxInfo::with_channel(channel.into()).into(),
2741 0.into(),
2742 )
2743 .await;
2744
2745 let msg = m
2747 .fake_device_state
2748 .lock()
2749 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
2750 .expect("expect ConnectConf");
2751 assert_eq!(
2752 msg,
2753 fidl_mlme::ConnectConfirm {
2754 peer_sta_address: BSSID.to_array(),
2755 result_code: fidl_ieee80211::StatusCode::Success,
2756 association_id: 42,
2757 association_ies: vec![
2758 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
2761 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2765 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
2769 }
2770 );
2771
2772 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
2774 }
2775
2776 #[fuchsia::test(allow_stalls = false)]
2777 async fn mlme_connect_protected_happy_path() {
2778 let mut m = MockObjects::new().await;
2779 let mut me = m.make_mlme().await;
2780 let channel = Channel::new(6, Cbw::Cbw40);
2781 let connect_req = fidl_mlme::ConnectRequest {
2782 selected_bss: fake_fidl_bss_description!(Wpa2,
2783 ssid: Ssid::try_from("ssid").unwrap().into(),
2784 bssid: BSSID.to_array(),
2785 channel: channel.clone(),
2786 ),
2787 connect_failure_timeout: 100,
2788 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
2789 sae_password: vec![],
2790 wep_key: None,
2791 security_ie: vec![
2792 48, 18, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 2, ],
2798 };
2799 me.handle_mlme_req(wlan_sme::MlmeRequest::Connect(connect_req))
2800 .await
2801 .expect("Failed to send MlmeRequest::Connect");
2802
2803 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
2805 assert_eq!(ids.len(), 1);
2806 });
2807
2808 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2810 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2811 #[rustfmt::skip]
2812 let expected = vec![
2813 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, ];
2825 assert_eq!(&frame[..], &expected[..]);
2826
2827 #[rustfmt::skip]
2829 let auth_resp_success = vec![
2830 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, ];
2842 me.on_mac_frame_rx(
2843 &auth_resp_success[..],
2844 MockWlanRxInfo::with_channel(channel.into()).into(),
2845 0.into(),
2846 )
2847 .await;
2848
2849 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2851 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2852 #[rustfmt::skip]
2853 let expected = vec![
2854 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, ];
2881 assert_eq!(&frame[..], &expected[..]);
2882
2883 #[rustfmt::skip]
2885 let assoc_resp_success = vec![
2886 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,
2900 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, ];
2913 me.on_mac_frame_rx(
2914 &assoc_resp_success[..],
2915 MockWlanRxInfo::with_channel(channel.into()).into(),
2916 0.into(),
2917 )
2918 .await;
2919
2920 let msg = m
2922 .fake_device_state
2923 .lock()
2924 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
2925 .expect("expect ConnectConf");
2926 assert_eq!(
2927 msg,
2928 fidl_mlme::ConnectConfirm {
2929 peer_sta_address: BSSID.to_array(),
2930 result_code: fidl_ieee80211::StatusCode::Success,
2931 association_id: 42,
2932 association_ies: vec![
2933 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,
2944 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
2949 }
2950 );
2951
2952 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::DOWN);
2954
2955 me.handle_mlme_req(wlan_sme::MlmeRequest::SetCtrlPort(
2957 fidl_mlme::SetControlledPortRequest {
2958 peer_sta_address: BSSID.to_array(),
2959 state: fidl_mlme::ControlledPortState::Open,
2960 },
2961 ))
2962 .await
2963 .expect("expect sending msg to succeed");
2964
2965 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
2967 }
2968
2969 #[fuchsia::test(allow_stalls = false)]
2970 async fn mlme_connect_vht() {
2971 let mut m = MockObjects::new().await;
2972 let mut me = m.make_mlme().await;
2973 let channel = Channel::new(36, Cbw::Cbw40);
2974 let connect_req = fidl_mlme::ConnectRequest {
2975 selected_bss: fake_fidl_bss_description!(Open,
2976 ssid: Ssid::try_from("ssid").unwrap().into(),
2977 bssid: BSSID.to_array(),
2978 channel: channel.clone(),
2979 ),
2980 connect_failure_timeout: 100,
2981 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
2982 sae_password: vec![],
2983 wep_key: None,
2984 security_ie: vec![],
2985 };
2986 me.handle_mlme_req(wlan_sme::MlmeRequest::Connect(connect_req))
2987 .await
2988 .expect("Failed to send MlmeRequest::Connect.");
2989
2990 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
2992 assert_eq!(ids.len(), 1);
2993 });
2994
2995 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2997 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2998
2999 #[rustfmt::skip]
3001 let auth_resp_success = vec![
3002 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, ];
3014 me.on_mac_frame_rx(
3015 &auth_resp_success[..],
3016 MockWlanRxInfo::with_channel(channel.into()).into(),
3017 0.into(),
3018 )
3019 .await;
3020
3021 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
3023 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
3024 #[rustfmt::skip]
3025 let expected = vec![
3026 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, ];
3048 assert_eq!(&frame[..], &expected[..]);
3049 }
3050
3051 #[fuchsia::test(allow_stalls = false)]
3052 async fn mlme_connect_timeout() {
3053 let mut m = MockObjects::new().await;
3054 let mut me = m.make_mlme().await;
3055 let connect_req = fidl_mlme::ConnectRequest {
3056 selected_bss: fake_fidl_bss_description!(Open, bssid: BSSID.to_array()),
3057 connect_failure_timeout: 100,
3058 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
3059 sae_password: vec![],
3060 wep_key: None,
3061 security_ie: vec![],
3062 };
3063 me.handle_mlme_req(wlan_sme::MlmeRequest::Connect(connect_req))
3064 .await
3065 .expect("Failed to send MlmeRequest::Connect.");
3066
3067 let (event, _id) = assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(events) => {
3069 assert_eq!(events.len(), 1);
3070 events[0].clone()
3071 });
3072
3073 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
3075 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
3076
3077 me.handle_timed_event(event).await;
3079
3080 let msg = m
3082 .fake_device_state
3083 .lock()
3084 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
3085 .expect("expect msg");
3086 assert_eq!(
3087 msg,
3088 fidl_mlme::ConnectConfirm {
3089 peer_sta_address: BSSID.to_array(),
3090 result_code: fidl_ieee80211::StatusCode::RejectedSequenceTimeout,
3091 association_id: 0,
3092 association_ies: vec![],
3093 },
3094 );
3095 }
3096
3097 #[fuchsia::test(allow_stalls = false)]
3098 async fn mlme_reconnect_no_sta() {
3099 let mut m = MockObjects::new().await;
3100 let mut me = m.make_mlme().await;
3101
3102 let reconnect_req = fidl_mlme::ReconnectRequest { peer_sta_address: [1, 2, 3, 4, 5, 6] };
3103 let result = me.handle_mlme_req(wlan_sme::MlmeRequest::Reconnect(reconnect_req)).await;
3104 assert_matches!(result, Err(Error::Status(_, zx::Status::BAD_STATE)));
3105
3106 let msg = m
3108 .fake_device_state
3109 .lock()
3110 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
3111 .expect("expect msg");
3112 assert_eq!(
3113 msg,
3114 fidl_mlme::ConnectConfirm {
3115 peer_sta_address: [1, 2, 3, 4, 5, 6],
3116 result_code: fidl_ieee80211::StatusCode::DeniedNoAssociationExists,
3117 association_id: 0,
3118 association_ies: vec![],
3119 },
3120 );
3121 }
3122
3123 #[fuchsia::test(allow_stalls = false)]
3124 async fn mlme_respond_to_get_iface_stats_with_error_status() {
3125 let mut m = MockObjects::new().await;
3126 let mut me = m.make_mlme().await;
3127
3128 let (responder, receiver) = Responder::new();
3129 me.handle_mlme_req(wlan_sme::MlmeRequest::GetIfaceStats(responder))
3130 .await
3131 .expect("Failed to send MlmeRequest::GetIfaceStats.");
3132 assert_eq!(
3133 receiver.await,
3134 Ok(fidl_mlme::GetIfaceStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED))
3135 );
3136 }
3137
3138 #[fuchsia::test(allow_stalls = false)]
3139 async fn mlme_respond_to_get_iface_histogram_stats_with_error_status() {
3140 let mut m = MockObjects::new().await;
3141 let mut me = m.make_mlme().await;
3142
3143 let (responder, receiver) = Responder::new();
3144 me.handle_mlme_req(wlan_sme::MlmeRequest::GetIfaceHistogramStats(responder))
3145 .await
3146 .expect("Failed to send MlmeRequest::GetIfaceHistogramStats");
3147 assert_eq!(
3148 receiver.await,
3149 Ok(fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(
3150 zx::sys::ZX_ERR_NOT_SUPPORTED
3151 ))
3152 );
3153 }
3154
3155 #[test]
3156 fn drop_mgmt_frame_wrong_bssid() {
3157 let frame = [
3158 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0x10, 0, ];
3166 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3167 assert_eq!(false, make_client_station().should_handle_frame(&frame));
3168 }
3169
3170 #[test]
3171 fn drop_mgmt_frame_wrong_dst_addr() {
3172 let frame = [
3173 0b11010000, 0b00000000, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3181 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3182 assert_eq!(false, make_client_station().should_handle_frame(&frame));
3183 }
3184
3185 #[test]
3186 fn mgmt_frame_ok_broadcast() {
3187 let frame = [
3188 0b11010000, 0b00000000, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3196 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3197 assert_eq!(true, make_client_station().should_handle_frame(&frame));
3198 }
3199
3200 #[test]
3201 fn mgmt_frame_ok_client_addr() {
3202 let frame = [
3203 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3211 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3212 assert_eq!(true, make_client_station().should_handle_frame(&frame));
3213 }
3214
3215 #[test]
3216 fn drop_data_frame_wrong_bssid() {
3217 let frame = [
3218 0b01001000,
3220 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3227 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3228 assert_eq!(false, make_client_station().should_handle_frame(&frame));
3229 }
3230
3231 #[test]
3232 fn drop_data_frame_wrong_dst_addr() {
3233 let frame = [
3234 0b01001000,
3236 0b00000010, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3243 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3244 assert_eq!(false, make_client_station().should_handle_frame(&frame));
3245 }
3246
3247 #[test]
3248 fn data_frame_ok_broadcast() {
3249 let frame = [
3250 0b01001000,
3252 0b00000010, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3259 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3260 assert_eq!(true, make_client_station().should_handle_frame(&frame));
3261 }
3262
3263 #[test]
3264 fn data_frame_ok_client_addr() {
3265 let frame = [
3266 0b01001000,
3268 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3275 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3276 assert_eq!(true, make_client_station().should_handle_frame(&frame));
3277 }
3278}