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 fidl_fuchsia_wlan_common as fidl_common;
22use fidl_fuchsia_wlan_driver as fidl_driver_common;
23use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
24use fidl_fuchsia_wlan_internal as fidl_internal;
25use fidl_fuchsia_wlan_minstrel as fidl_minstrel;
26use fidl_fuchsia_wlan_mlme as fidl_mlme;
27use fidl_fuchsia_wlan_softmac as fidl_softmac;
28use fuchsia_trace as trace;
29use ieee80211::{Bssid, MacAddr, MacAddrBytes, Ssid};
30use log::{error, warn};
31use scanner::Scanner;
32use state::States;
33use std::mem;
34use std::ptr::NonNull;
35use wlan_common::append::Append;
36use wlan_common::bss::BssDescription;
37use wlan_common::buffer_writer::BufferWriter;
38use wlan_common::capabilities::{ClientCapabilities, derive_join_capabilities};
39use wlan_common::channel::Channel;
40use wlan_common::ie::rsn::rsne;
41use wlan_common::ie::{self, Id};
42use wlan_common::mac::{self, Aid, CapabilityInfo};
43use wlan_common::sequence::SequenceManager;
44use wlan_common::time::TimeUnit;
45use wlan_common::timer::{EventHandle, Timer};
46use wlan_common::{data_writer, mgmt_writer, wmm};
47use wlan_frame_writer::{append_frame_to, write_frame, write_frame_with_fixed_slice};
48use wlan_trace as wtrace;
49use zerocopy::SplitByteSlice;
50
51pub use scanner::ScanError;
52
53#[derive(Debug, Clone, PartialEq)]
54pub enum TimedEvent {
55 Connecting,
57 Reassociating,
59 AssociationStatusCheck,
62 ChannelSwitch,
64}
65
66#[cfg(test)]
67impl TimedEvent {
68 fn class(&self) -> TimedEventClass {
69 match self {
70 Self::Connecting => TimedEventClass::Connecting,
71 Self::Reassociating => TimedEventClass::Reassociating,
72 Self::AssociationStatusCheck => TimedEventClass::AssociationStatusCheck,
73 Self::ChannelSwitch => TimedEventClass::ChannelSwitch,
74 }
75 }
76}
77
78#[cfg(test)]
79#[derive(Debug, PartialEq, Eq, Hash)]
80pub enum TimedEventClass {
81 Connecting,
82 Reassociating,
83 AssociationStatusCheck,
84 ChannelSwitch,
85}
86
87#[repr(C)]
90#[derive(Debug, Clone, Default)]
91pub struct ClientConfig {
92 pub ensure_on_channel_time: zx::sys::zx_duration_t,
93}
94
95pub struct Context<D> {
96 _config: ClientConfig,
97 device: D,
98 timer: Timer<TimedEvent>,
99 seq_mgr: SequenceManager,
100}
101
102pub struct ClientMlme<D> {
103 sta: Option<Client>,
104 ctx: Context<D>,
105 scanner: Scanner,
106 channel_state: ChannelState,
107}
108
109impl<D: DeviceOps> crate::MlmeImpl for ClientMlme<D> {
110 type Config = ClientConfig;
111 type Device = D;
112 type TimerEvent = TimedEvent;
113 async fn new(
114 config: Self::Config,
115 device: Self::Device,
116 timer: Timer<TimedEvent>,
117 ) -> Result<Self, anyhow::Error> {
118 Self::new(config, device, timer).await.map_err(From::from)
119 }
120 async fn handle_mlme_request(
121 &mut self,
122 req: wlan_sme::MlmeRequest,
123 ) -> Result<(), anyhow::Error> {
124 Self::handle_mlme_req(self, req).await.map_err(From::from)
125 }
126 async fn handle_mac_frame_rx(
127 &mut self,
128 bytes: &[u8],
129 rx_info: fidl_softmac::WlanRxInfo,
130 async_id: trace::Id,
131 ) {
132 wtrace::duration!("ClientMlme::handle_mac_frame_rx");
133 Self::on_mac_frame_rx(self, bytes, rx_info, async_id).await
134 }
135 fn handle_eth_frame_tx(
136 &mut self,
137 bytes: &[u8],
138 async_id: trace::Id,
139 ) -> Result<(), anyhow::Error> {
140 wtrace::duration!("ClientMlme::handle_eth_frame_tx");
141 Self::on_eth_frame_tx(self, bytes, async_id).map_err(From::from)
142 }
143 async fn handle_scan_complete(&mut self, status: zx::Status, scan_id: u64) {
144 Self::handle_scan_complete(self, status, scan_id).await;
145 }
146 async fn handle_timeout(&mut self, event: TimedEvent) {
147 Self::handle_timed_event(self, event).await
148 }
149 fn access_device(&mut self) -> &mut Self::Device {
150 &mut self.ctx.device
151 }
152}
153
154impl<D> ClientMlme<D> {
155 pub fn seq_mgr(&mut self) -> &mut SequenceManager {
156 &mut self.ctx.seq_mgr
157 }
158
159 fn on_sme_get_iface_stats(
160 &self,
161 responder: wlan_sme::responder::Responder<fidl_mlme::GetIfaceStatsResponse>,
162 ) -> Result<(), Error> {
163 let resp = fidl_mlme::GetIfaceStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED);
165 responder.respond(resp);
166 Ok(())
167 }
168
169 fn on_sme_get_iface_histogram_stats(
170 &self,
171 responder: wlan_sme::responder::Responder<fidl_mlme::GetIfaceHistogramStatsResponse>,
172 ) -> Result<(), Error> {
173 let resp =
175 fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED);
176 responder.respond(resp);
177 Ok(())
178 }
179
180 fn on_sme_list_minstrel_peers(
181 &self,
182 responder: wlan_sme::responder::Responder<fidl_mlme::MinstrelListResponse>,
183 ) -> Result<(), Error> {
184 error!("ListMinstrelPeers is not supported.");
186 let peers = fidl_minstrel::Peers { addrs: vec![] };
187 let resp = fidl_mlme::MinstrelListResponse { peers };
188 responder.respond(resp);
189 Ok(())
190 }
191
192 fn on_sme_get_minstrel_stats(
193 &self,
194 responder: wlan_sme::responder::Responder<fidl_mlme::MinstrelStatsResponse>,
195 _addr: &MacAddr,
196 ) -> Result<(), Error> {
197 error!("GetMinstrelStats is not supported.");
199 let resp = fidl_mlme::MinstrelStatsResponse { peer: None };
200 responder.respond(resp);
201 Ok(())
202 }
203}
204
205impl<D: DeviceOps> ClientMlme<D> {
206 pub async fn new(
207 config: ClientConfig,
208 mut device: D,
209 timer: Timer<TimedEvent>,
210 ) -> Result<Self, Error> {
211 let iface_mac = device::try_query_iface_mac(&mut device).await?;
212 Ok(Self {
213 sta: None,
214 ctx: Context { _config: config, device, timer, seq_mgr: SequenceManager::new() },
215 scanner: Scanner::new(iface_mac.into()),
216 channel_state: Default::default(),
217 })
218 }
219
220 pub async fn set_main_channel(
221 &mut self,
222 channel: fidl_ieee80211::WlanChannel,
223 ) -> Result<(), zx::Status> {
224 self.channel_state.bind(&mut self.ctx, &mut self.scanner).set_main_channel(channel).await
225 }
226
227 pub async fn on_mac_frame_rx(
228 &mut self,
229 frame: &[u8],
230 rx_info: fidl_softmac::WlanRxInfo,
231 async_id: trace::Id,
232 ) {
233 wtrace::duration!("ClientMlme::on_mac_frame_rx");
234 if let Some(mgmt_frame) = mac::MgmtFrame::parse(frame, false) {
236 let bssid = Bssid::from(mgmt_frame.mgmt_hdr.addr3);
237 match mgmt_frame.try_into_mgmt_body().1 {
238 Some(mac::MgmtBody::Beacon { bcn_hdr, elements }) => {
239 wtrace::duration!("MgmtBody::Beacon");
240 self.scanner.bind(&mut self.ctx).handle_ap_advertisement(
241 bssid,
242 bcn_hdr.beacon_interval,
243 bcn_hdr.capabilities,
244 elements,
245 rx_info.clone(),
246 );
247 }
248 Some(mac::MgmtBody::ProbeResp { probe_resp_hdr, elements }) => {
249 wtrace::duration!("MgmtBody::ProbeResp");
250 self.scanner.bind(&mut self.ctx).handle_ap_advertisement(
251 bssid,
252 probe_resp_hdr.beacon_interval,
253 probe_resp_hdr.capabilities,
254 elements,
255 rx_info.clone(),
256 )
257 }
258 _ => (),
259 }
260 }
261
262 if let Some(sta) = self.sta.as_mut() {
263 match self.channel_state.get_main_channel() {
267 Some(main_channel) if main_channel.primary == rx_info.channel.primary => {
268 sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
269 .on_mac_frame(frame, rx_info, async_id)
270 .await
271 }
272 Some(_) => {
273 wtrace::async_end_wlansoftmac_rx(async_id, "off main channel");
274 }
275 None => {
278 error!(
279 "Received MAC frame on channel {:?} while main channel is not set.",
280 rx_info.channel
281 );
282 wtrace::async_end_wlansoftmac_rx(async_id, "main channel not set");
283 }
284 }
285 } else {
286 wtrace::async_end_wlansoftmac_rx(async_id, "no bound client");
287 }
288 }
289
290 pub async fn handle_mlme_req(&mut self, req: wlan_sme::MlmeRequest) -> Result<(), Error> {
291 use wlan_sme::MlmeRequest as Req;
292
293 match req {
294 Req::Scan(req) => Ok(self.on_sme_scan(req).await),
296 Req::Connect(req) => self.on_sme_connect(req).await,
297 Req::GetIfaceStats(responder) => self.on_sme_get_iface_stats(responder),
298 Req::GetIfaceHistogramStats(responder) => {
299 self.on_sme_get_iface_histogram_stats(responder)
300 }
301 Req::QueryDeviceInfo(responder) => self.on_sme_query_device_info(responder).await,
302 Req::QueryMacSublayerSupport(responder) => {
303 self.on_sme_query_mac_sublayer_support(responder).await
304 }
305 Req::QuerySecuritySupport(responder) => {
306 self.on_sme_query_security_support(responder).await
307 }
308 Req::QuerySpectrumManagementSupport(responder) => {
309 self.on_sme_query_spectrum_management_support(responder).await
310 }
311 Req::ListMinstrelPeers(responder) => self.on_sme_list_minstrel_peers(responder),
312 Req::GetMinstrelStats(req, responder) => {
313 self.on_sme_get_minstrel_stats(responder, &req.peer_addr.into())
314 }
315 other_message => match &mut self.sta {
316 None => {
317 if let Req::Reconnect(req) = other_message {
318 self.ctx.device.send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf {
319 resp: fidl_mlme::ConnectConfirm {
320 peer_sta_address: req.peer_sta_address,
321 result_code: fidl_ieee80211::StatusCode::DeniedNoAssociationExists,
322 association_id: 0,
323 association_ies: vec![],
324 },
325 })?;
326 }
327 Err(Error::Status(
328 format!(
329 "Failed to handle {} MLME request when this ClientMlme has no sta.",
330 other_message.name()
331 ),
332 zx::Status::BAD_STATE,
333 ))
334 }
335 Some(sta) => Ok(sta
336 .bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
337 .handle_mlme_req(other_message)
338 .await),
339 },
340 }
341 }
342
343 async fn on_sme_scan(&mut self, req: fidl_mlme::ScanRequest) {
344 let txn_id = req.txn_id;
345 let _ = self.scanner.bind(&mut self.ctx).on_sme_scan(req).await.map_err(|e| {
346 error!("Scan failed in MLME: {:?}", e);
347 let code = match e {
348 Error::ScanError(scan_error) => scan_error.into(),
349 _ => fidl_mlme::ScanResultCode::InternalError,
350 };
351 self.ctx
352 .device
353 .send_mlme_event(fidl_mlme::MlmeEvent::OnScanEnd {
354 end: fidl_mlme::ScanEnd { txn_id, code },
355 })
356 .unwrap_or_else(|e| error!("error sending MLME ScanEnd: {}", e));
357 });
358 }
359
360 pub async fn handle_scan_complete(&mut self, status: zx::Status, scan_id: u64) {
361 self.scanner.bind(&mut self.ctx).handle_scan_complete(status, scan_id).await;
362 }
363
364 async fn on_sme_connect(&mut self, req: fidl_mlme::ConnectRequest) -> Result<(), Error> {
365 if let Err(e) = self.scanner.bind(&mut self.ctx).cancel_ongoing_scan().await {
368 warn!("Failed to cancel ongoing scan before connect: {}.", e);
369 }
370
371 let bssid = req.selected_bss.bssid;
372 let result = match req.selected_bss.try_into() {
373 Ok(bss) => {
374 let req = ParsedConnectRequest {
375 selected_bss: bss,
376 connect_failure_timeout: req.connect_failure_timeout,
377 auth_type: req.auth_type,
378 sae_password: req.sae_password,
379 wep_key: req.wep_key.map(|k| *k),
380 security_ie: req.security_ie,
381 owe_public_key: req.owe_public_key.map(|k| *k),
382 };
383 self.join_device(&req.selected_bss).await.map(|cap| (req, cap))
384 }
385 Err(e) => Err(Error::Status(
386 format!("Error parsing BssDescription: {:?}", e),
387 zx::Status::IO_INVALID,
388 )),
389 };
390
391 match result {
392 Ok((req, client_capabilities)) => {
393 self.sta.replace(Client::new(
394 req,
395 device::try_query_iface_mac(&mut self.ctx.device).await?,
396 client_capabilities,
397 ));
398 if let Some(sta) = &mut self.sta {
399 sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
400 .start_connecting()
401 .await;
402 }
403 Ok(())
404 }
405 Err(e) => {
406 error!("Error setting up device for join: {}", e);
407 self.ctx.device.send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf {
410 resp: fidl_mlme::ConnectConfirm {
411 peer_sta_address: bssid,
412 result_code: fidl_ieee80211::StatusCode::JoinFailure,
413 association_id: 0,
414 association_ies: vec![],
415 },
416 })?;
417 Err(e)
418 }
419 }
420 }
421
422 async fn join_device(&mut self, bss: &BssDescription) -> Result<ClientCapabilities, Error> {
423 let info = ddk_converter::mlme_device_info_from_softmac(
424 device::try_query(&mut self.ctx.device).await?,
425 )?;
426 let join_caps = derive_join_capabilities(Channel::from(bss.channel), bss.rates(), &info)
427 .map_err(|e| {
428 Error::Status(
429 format!("Failed to derive join capabilities: {:?}", e),
430 zx::Status::NOT_SUPPORTED,
431 )
432 })?;
433
434 self.set_main_channel(bss.channel.into())
435 .await
436 .map_err(|status| Error::Status(format!("Error setting device channel"), status))?;
437
438 let join_bss_request = fidl_driver_common::JoinBssRequest {
439 bssid: Some(bss.bssid.to_array()),
440 bss_type: Some(fidl_ieee80211::BssType::Infrastructure),
441 remote: Some(true),
442 beacon_period: Some(bss.beacon_period),
443 ..Default::default()
444 };
445
446 self.ctx
448 .device
449 .join_bss(&join_bss_request)
450 .await
451 .map(|()| join_caps)
452 .map_err(|status| Error::Status(format!("Error setting BSS in driver"), status))
453 }
454
455 async fn on_sme_query_device_info(
456 &mut self,
457 responder: wlan_sme::responder::Responder<fidl_mlme::DeviceInfo>,
458 ) -> Result<(), Error> {
459 let info = ddk_converter::mlme_device_info_from_softmac(
460 device::try_query(&mut self.ctx.device).await?,
461 )?;
462 responder.respond(info);
463 Ok(())
464 }
465
466 async fn on_sme_query_mac_sublayer_support(
467 &mut self,
468 responder: wlan_sme::responder::Responder<fidl_common::MacSublayerSupport>,
469 ) -> Result<(), Error> {
470 let support = device::try_query_mac_sublayer_support(&mut self.ctx.device).await?;
471 responder.respond(support);
472 Ok(())
473 }
474
475 async fn on_sme_query_security_support(
476 &mut self,
477 responder: wlan_sme::responder::Responder<fidl_common::SecuritySupport>,
478 ) -> Result<(), Error> {
479 let support = device::try_query_security_support(&mut self.ctx.device).await?;
480 responder.respond(support);
481 Ok(())
482 }
483
484 async fn on_sme_query_spectrum_management_support(
485 &mut self,
486 responder: wlan_sme::responder::Responder<fidl_common::SpectrumManagementSupport>,
487 ) -> Result<(), Error> {
488 let support = device::try_query_spectrum_management_support(&mut self.ctx.device).await?;
489 responder.respond(support);
490 Ok(())
491 }
492
493 pub fn on_eth_frame_tx<B: SplitByteSlice>(
494 &mut self,
495 bytes: B,
496 async_id: trace::Id,
497 ) -> Result<(), Error> {
498 wtrace::duration!("ClientMlme::on_eth_frame_tx");
499 match self.sta.as_mut() {
500 None => Err(Error::Status(
501 format!("Ethernet frame dropped (Client does not exist)."),
502 zx::Status::BAD_STATE,
503 )),
504 Some(sta) => sta
505 .bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
506 .on_eth_frame_tx(bytes, async_id),
507 }
508 }
509
510 pub async fn handle_timed_event(&mut self, event: TimedEvent) {
513 if let Some(sta) = self.sta.as_mut() {
514 return sta
515 .bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
516 .handle_timed_event(event)
517 .await;
518 }
519 }
520}
521
522pub struct Client {
526 state: Option<States>,
527 pub connect_req: ParsedConnectRequest,
528 pub iface_mac: MacAddr,
529 pub client_capabilities: ClientCapabilities,
530 pub connect_timeout: Option<EventHandle>,
531}
532
533impl Client {
534 pub fn new(
535 connect_req: ParsedConnectRequest,
536 iface_mac: MacAddr,
537 client_capabilities: ClientCapabilities,
538 ) -> Self {
539 Self {
540 state: Some(States::new_initial()),
541 connect_req,
542 iface_mac,
543 client_capabilities,
544 connect_timeout: None,
545 }
546 }
547
548 pub fn ssid(&self) -> &Ssid {
549 &self.connect_req.selected_bss.ssid
550 }
551
552 pub fn bssid(&self) -> Bssid {
553 self.connect_req.selected_bss.bssid
554 }
555
556 pub fn beacon_period(&self) -> zx::MonotonicDuration {
557 zx::MonotonicDuration::from(TimeUnit(self.connect_req.selected_bss.beacon_period))
558 }
559
560 pub fn eapol_required(&self) -> bool {
561 self.connect_req.selected_bss.rsne().is_some()
562 || self.connect_req.selected_bss.find_wpa_ie().is_some()
566 }
567
568 pub fn bind<'a, D>(
569 &'a mut self,
570 ctx: &'a mut Context<D>,
571 scanner: &'a mut Scanner,
572 channel_state: &'a mut ChannelState,
573 ) -> BoundClient<'a, D> {
574 BoundClient { sta: self, ctx, scanner, channel_state }
575 }
576
577 fn should_handle_frame<B: SplitByteSlice>(&self, mac_frame: &mac::MacFrame<B>) -> bool {
581 wtrace::duration!("Client::should_handle_frame");
582
583 let (src_addr, dst_addr) = match mac_frame {
586 mac::MacFrame::Mgmt(mac::MgmtFrame { mgmt_hdr, .. }) => {
587 (Some(mgmt_hdr.addr3), mgmt_hdr.addr1)
588 }
589 mac::MacFrame::Data(mac::DataFrame { fixed_fields, .. }) => {
590 (mac::data_bssid(&fixed_fields), mac::data_dst_addr(&fixed_fields))
591 }
592 _ => return false,
594 };
595 src_addr.is_some_and(|src_addr| src_addr == self.bssid().into())
596 && (!dst_addr.is_unicast() || dst_addr == self.iface_mac)
597 }
598}
599
600pub struct BoundClient<'a, D> {
601 sta: &'a mut Client,
602 ctx: &'a mut Context<D>,
604 scanner: &'a mut Scanner,
605 channel_state: &'a mut ChannelState,
606}
607
608impl<'a, D: DeviceOps> akm_algorithm::AkmAction for BoundClient<'a, D> {
609 fn send_auth_frame(
610 &mut self,
611 auth_type: mac::AuthAlgorithmNumber,
612 seq_num: u16,
613 result_code: mac::StatusCode,
614 auth_content: &[u8],
615 ) -> Result<(), anyhow::Error> {
616 self.send_auth_frame(auth_type, seq_num, result_code, auth_content).map_err(|e| e.into())
617 }
618
619 fn forward_sme_sae_rx(
620 &mut self,
621 seq_num: u16,
622 status_code: fidl_ieee80211::StatusCode,
623 sae_fields: Vec<u8>,
624 ) {
625 self.forward_sae_frame_rx(seq_num, status_code, sae_fields)
626 }
627
628 fn forward_sae_handshake_ind(&mut self) {
629 self.forward_sae_handshake_ind()
630 }
631}
632
633impl<'a, D: DeviceOps> BoundClient<'a, D> {
634 fn deliver_msdu<B: SplitByteSlice>(&mut self, msdu: mac::Msdu<B>) -> Result<(), Error> {
638 let mac::Msdu { dst_addr, src_addr, llc_frame } = msdu;
639
640 let mut packet = [0u8; mac::MAX_ETH_FRAME_LEN];
641 let (frame_start, frame_end) = write_frame_with_fixed_slice!(&mut packet[..], {
642 headers: {
643 mac::EthernetIIHdr: &mac::EthernetIIHdr {
644 da: dst_addr,
645 sa: src_addr,
646 ether_type: llc_frame.hdr.protocol_id,
647 },
648 },
649 payload: &llc_frame.body,
650 })?;
651 self.ctx
652 .device
653 .deliver_eth_frame(&packet[frame_start..frame_end])
654 .map_err(|s| Error::Status(format!("could not deliver Ethernet II frame"), s))
655 }
656
657 pub fn send_auth_frame(
658 &mut self,
659 auth_type: mac::AuthAlgorithmNumber,
660 seq_num: u16,
661 result_code: mac::StatusCode,
662 auth_content: &[u8],
663 ) -> Result<(), Error> {
664 let buffer = write_frame!({
665 headers: {
666 mac::MgmtHdr: &mgmt_writer::mgmt_hdr_to_ap(
667 mac::FrameControl(0)
668 .with_frame_type(mac::FrameType::MGMT)
669 .with_mgmt_subtype(mac::MgmtSubtype::AUTH),
670 self.sta.bssid(),
671 self.sta.iface_mac,
672 mac::SequenceControl(0)
673 .with_seq_num(self.ctx.seq_mgr.next_sns1(&self.sta.bssid().into()) as u16)
674 ),
675 mac::AuthHdr: &mac::AuthHdr {
676 auth_alg_num: auth_type,
677 auth_txn_seq_num: seq_num,
678 status_code: result_code,
679 },
680 },
681 body: auth_content,
682 })?;
683 self.send_mgmt_or_ctrl_frame(buffer)
684 .map_err(|s| Error::Status(format!("error sending open auth frame"), s))
685 }
686
687 pub fn send_open_auth_frame(&mut self) -> Result<(), Error> {
689 self.send_auth_frame(
690 mac::AuthAlgorithmNumber::OPEN,
691 1,
692 fidl_ieee80211::StatusCode::Success.into(),
693 &[],
694 )
695 }
696
697 pub fn send_assoc_req_frame(&mut self) -> Result<(), Error> {
699 let ssid = self.sta.ssid().clone();
700 let cap = &self.sta.client_capabilities.0;
701 let capability_info = cap.capability_info.0;
702 let rates: Vec<u8> = cap.rates.iter().map(|r| r.rate()).collect();
703 let ht_cap = cap.ht_cap;
704 let vht_cap = cap.vht_cap;
705 let security_ie = self.sta.connect_req.security_ie.clone();
706
707 let rsne = (!security_ie.is_empty() && security_ie[0] == ie::Id::RSNE.0)
708 .then(|| match rsne::from_bytes(&security_ie[..]) {
709 Ok((_, x)) => Ok(x),
710 Err(e) => Err(format_err!("error parsing rsne {:?} : {:?}", security_ie, e)),
711 })
712 .transpose()?;
713 let buffer = write_frame!({
714 headers: {
715 mac::MgmtHdr: &mgmt_writer::mgmt_hdr_to_ap(
716 mac::FrameControl(0)
717 .with_frame_type(mac::FrameType::MGMT)
718 .with_mgmt_subtype(mac::MgmtSubtype::ASSOC_REQ),
719 self.sta.bssid(),
720 self.sta.iface_mac,
721 mac::SequenceControl(0)
722 .with_seq_num(self.ctx.seq_mgr.next_sns1(&self.sta.bssid().into()) as u16)
723 ),
724 mac::AssocReqHdr: &mac::AssocReqHdr {
725 capabilities: mac::CapabilityInfo(capability_info),
726 listen_interval: 0,
727 },
728 },
729 ies: {
730 ssid: ssid,
731 supported_rates: rates,
732 extended_supported_rates: {},
733 rsne?: rsne,
734 ht_cap?: ht_cap,
735 vht_cap?: vht_cap,
736 },
737 })?;
738 self.send_mgmt_or_ctrl_frame(buffer)
739 .map_err(|s| Error::Status(format!("error sending assoc req frame"), s))
740 }
741
742 fn send_keep_alive_resp_frame(&mut self) -> Result<(), Error> {
748 let buffer = write_frame!({
749 headers: {
750 mac::FixedDataHdrFields: &data_writer::data_hdr_client_to_ap(
751 mac::FrameControl(0)
752 .with_frame_type(mac::FrameType::DATA)
753 .with_data_subtype(mac::DataSubtype(0).with_null(true)),
754 self.sta.bssid(),
755 self.sta.iface_mac,
756 mac::SequenceControl(0)
757 .with_seq_num(self.ctx.seq_mgr.next_sns1(&self.sta.bssid().into()) as u16)
758 ),
759 },
760 })?;
761 self.ctx
762 .device
763 .send_wlan_frame(buffer, fidl_softmac::WlanTxInfoFlags::empty(), None)
764 .map_err(|s| Error::Status(format!("error sending keep alive frame"), s))
765 }
766
767 pub fn send_deauth_frame(&mut self, reason_code: mac::ReasonCode) -> Result<(), Error> {
768 let buffer = write_frame!({
769 headers: {
770 mac::MgmtHdr: &mgmt_writer::mgmt_hdr_to_ap(
771 mac::FrameControl(0)
772 .with_frame_type(mac::FrameType::MGMT)
773 .with_mgmt_subtype(mac::MgmtSubtype::DEAUTH),
774 self.sta.bssid(),
775 self.sta.iface_mac,
776 mac::SequenceControl(0)
777 .with_seq_num(self.ctx.seq_mgr.next_sns1(&self.sta.bssid().into()) as u16)
778 ),
779 mac::DeauthHdr: &mac::DeauthHdr {
780 reason_code,
781 },
782 },
783 })?;
784 let result = self
785 .send_mgmt_or_ctrl_frame(buffer)
786 .map_err(|s| Error::Status(format!("error sending deauthenticate frame"), s));
787 self.channel_state.bind(&mut self.ctx, &mut self.scanner).clear_main_channel();
789
790 result
791 }
792
793 pub fn send_data_frame(
797 &mut self,
798 src: MacAddr,
799 dst: MacAddr,
800 is_protected: bool,
801 qos_ctrl: bool,
802 ether_type: u16,
803 payload: &[u8],
804 async_id: Option<trace::Id>,
805 ) -> Result<(), Error> {
806 let async_id_provided = async_id.is_some();
807 let async_id = async_id.unwrap_or_else(|| {
808 let async_id = trace::Id::new();
809 wtrace::async_begin_wlansoftmac_tx(async_id, "mlme");
810 async_id
811 });
812 wtrace::duration!("BoundClient::send_data_frame");
813
814 let qos_ctrl = if qos_ctrl {
815 Some(
816 wmm::derive_tid(ether_type, payload)
817 .map_or(mac::QosControl(0), |tid| mac::QosControl(0).with_tid(tid as u16)),
818 )
819 } else {
820 None
821 };
822
823 let to_ds = true;
830 let from_ds = src != self.sta.iface_mac;
831 let addr1 = self.sta.bssid().into();
833 let addr2 = self.sta.iface_mac;
834 let addr3 = match (to_ds, from_ds) {
835 (false, false) => self.sta.bssid().into(),
836 (false, true) => src,
837 (true, _) => dst,
838 };
839 let addr4 = if from_ds && to_ds { Some(src) } else { None };
840
841 let tx_flags = match ether_type {
842 mac::ETHER_TYPE_EAPOL => fidl_softmac::WlanTxInfoFlags::FAVOR_RELIABILITY,
843 _ => fidl_softmac::WlanTxInfoFlags::empty(),
844 };
845
846 const MAX_HEADER_SIZE: usize = mem::size_of::<mac::FixedDataHdrFields>()
850 + mem::size_of::<MacAddr>()
851 + mem::size_of::<mac::QosControl>()
852 + mem::size_of::<mac::LlcHdr>();
853 let header_room = MAX_HEADER_SIZE + 100;
854 let arena = Arena::new();
855 let mut buffer = arena.insert_default_slice(header_room + payload.len());
856
857 let payload_start = buffer.len() - payload.len();
860 buffer[payload_start..].clone_from_slice(&payload[..]);
861
862 let (frame_start, _frame_end) =
863 write_frame_with_fixed_slice!(&mut buffer[..payload_start], {
864 fill_zeroes: (),
865 headers: {
866 mac::FixedDataHdrFields: &mac::FixedDataHdrFields {
867 frame_ctrl: mac::FrameControl(0)
868 .with_frame_type(mac::FrameType::DATA)
869 .with_data_subtype(mac::DataSubtype(0).with_qos(qos_ctrl.is_some()))
870 .with_protected(is_protected)
871 .with_to_ds(to_ds)
872 .with_from_ds(from_ds),
873 duration: 0,
874 addr1,
875 addr2,
876 addr3,
877 seq_ctrl: mac::SequenceControl(0).with_seq_num(
878 match qos_ctrl.as_ref() {
879 None => self.ctx.seq_mgr.next_sns1(&dst),
880 Some(qos_ctrl) => self.ctx.seq_mgr.next_sns2(&dst, qos_ctrl.tid()),
881 } as u16
882 )
883 },
884 mac::Addr4?: addr4,
885 mac::QosControl?: qos_ctrl,
886 mac::LlcHdr: &data_writer::make_snap_llc_hdr(ether_type),
887 },
888 })
889 .map_err(|e| {
890 if !async_id_provided {
891 wtrace::async_end_wlansoftmac_tx(async_id, zx::Status::INTERNAL);
892 }
893 e
894 })?;
895
896 let buffer = unsafe {
900 arena.assume_unchecked(NonNull::new_unchecked(
901 &mut ArenaBox::into_ptr(buffer).as_mut()[frame_start..],
902 ))
903 };
904 let buffer = arena.make_static(buffer);
905 self.ctx.device.send_wlan_frame(buffer, tx_flags, Some(async_id)).map_err(|s| {
906 if !async_id_provided {
907 wtrace::async_end_wlansoftmac_tx(async_id, s);
908 }
909 Error::Status(format!("error sending data frame"), s)
910 })
911 }
912
913 fn send_eapol_indication(
916 &mut self,
917 src_addr: MacAddr,
918 dst_addr: MacAddr,
919 eapol_frame: &[u8],
920 ) -> Result<(), Error> {
921 self.ctx
922 .device
923 .send_mlme_event(fidl_mlme::MlmeEvent::EapolInd {
924 ind: fidl_mlme::EapolIndication {
925 src_addr: src_addr.to_array(),
926 dst_addr: dst_addr.to_array(),
927 data: eapol_frame.to_vec(),
928 },
929 })
930 .map_err(|e| e.into())
931 }
932
933 pub fn send_eapol_frame(
936 &mut self,
937 src: MacAddr,
938 dst: MacAddr,
939 is_protected: bool,
940 eapol_frame: &[u8],
941 ) {
942 let result = self.send_data_frame(
945 src,
946 dst,
947 is_protected,
948 false, mac::ETHER_TYPE_EAPOL,
950 eapol_frame,
951 None,
952 );
953 let result_code = match result {
954 Ok(()) => fidl_mlme::EapolResultCode::Success,
955 Err(e) => {
956 error!("error sending EAPoL frame: {}", e);
957 fidl_mlme::EapolResultCode::TransmissionFailure
958 }
959 };
960
961 self.ctx
963 .device
964 .send_mlme_event(fidl_mlme::MlmeEvent::EapolConf {
965 resp: fidl_mlme::EapolConfirm { result_code, dst_addr: dst.to_array() },
966 })
967 .unwrap_or_else(|e| error!("error sending MLME-EAPOL.confirm message: {}", e));
968 }
969
970 pub fn send_ps_poll_frame(&mut self, aid: Aid) -> Result<(), Error> {
971 const PS_POLL_ID_MASK: u16 = 0b11000000_00000000;
972
973 let buffer = write_frame!({
974 headers: {
975 mac::FrameControl: &mac::FrameControl(0)
976 .with_frame_type(mac::FrameType::CTRL)
977 .with_ctrl_subtype(mac::CtrlSubtype::PS_POLL),
978 mac::PsPoll: &mac::PsPoll {
979 masked_aid: aid | PS_POLL_ID_MASK,
982 bssid: self.sta.bssid(),
983 ta: self.sta.iface_mac,
984 },
985 },
986 })?;
987 self.send_mgmt_or_ctrl_frame(buffer)
988 .map_err(|s| Error::Status(format!("error sending PS-Poll frame"), s))
989 }
990
991 pub async fn handle_timed_event(&mut self, event: TimedEvent) {
993 self.sta.state = Some(self.sta.state.take().unwrap().on_timed_event(self, event).await)
994 }
995
996 pub async fn on_mac_frame<B: SplitByteSlice>(
998 &mut self,
999 bytes: B,
1000 rx_info: fidl_softmac::WlanRxInfo,
1001 async_id: trace::Id,
1002 ) {
1003 wtrace::duration!("BoundClient::on_mac_frame");
1004 self.sta.state =
1006 Some(self.sta.state.take().unwrap().on_mac_frame(self, bytes, rx_info, async_id).await);
1007 }
1008
1009 pub fn on_eth_frame_tx<B: SplitByteSlice>(
1010 &mut self,
1011 frame: B,
1012 async_id: trace::Id,
1013 ) -> Result<(), Error> {
1014 wtrace::duration!("BoundClient::on_eth_frame_tx");
1015 let state = self.sta.state.take().unwrap();
1017 let result = state.on_eth_frame(self, frame, async_id);
1018 self.sta.state.replace(state);
1019 result
1020 }
1021
1022 pub async fn start_connecting(&mut self) {
1023 let next_state = self.sta.state.take().unwrap().start_connecting(self).await;
1025 self.sta.state.replace(next_state);
1026 }
1027
1028 pub async fn handle_mlme_req(&mut self, msg: wlan_sme::MlmeRequest) {
1029 let next_state = self.sta.state.take().unwrap().handle_mlme_req(self, msg).await;
1031 self.sta.state.replace(next_state);
1032 }
1033
1034 fn send_connect_conf_failure(&mut self, result_code: fidl_ieee80211::StatusCode) {
1035 self.sta.connect_timeout.take();
1036 let bssid = self.sta.connect_req.selected_bss.bssid;
1037 self.send_connect_conf_failure_with_bssid(bssid, result_code);
1038 }
1039
1040 fn send_connect_conf_failure_with_bssid(
1043 &mut self,
1044 bssid: Bssid,
1045 result_code: fidl_ieee80211::StatusCode,
1046 ) {
1047 let connect_conf = fidl_mlme::ConnectConfirm {
1048 peer_sta_address: bssid.to_array(),
1049 result_code,
1050 association_id: 0,
1051 association_ies: vec![],
1052 };
1053 self.ctx
1054 .device
1055 .send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf { resp: connect_conf })
1056 .unwrap_or_else(|e| error!("error sending MLME-CONNECT.confirm: {}", e));
1057 }
1058
1059 fn send_connect_conf_success<B: SplitByteSlice>(
1060 &mut self,
1061 association_id: mac::Aid,
1062 association_ies: B,
1063 ) {
1064 self.sta.connect_timeout.take();
1065 let connect_conf = fidl_mlme::ConnectConfirm {
1066 peer_sta_address: self.sta.connect_req.selected_bss.bssid.to_array(),
1067 result_code: fidl_ieee80211::StatusCode::Success,
1068 association_id,
1069 association_ies: association_ies.to_vec(),
1070 };
1071 self.ctx
1072 .device
1073 .send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf { resp: connect_conf })
1074 .unwrap_or_else(|e| error!("error sending MLME-CONNECT.confirm: {}", e));
1075 }
1076
1077 fn send_deauthenticate_ind(
1079 &mut self,
1080 reason_code: fidl_ieee80211::ReasonCode,
1081 locally_initiated: LocallyInitiated,
1082 ) {
1083 self.channel_state.bind(&mut self.ctx, &mut self.scanner).clear_main_channel();
1085
1086 self.ctx
1087 .device
1088 .send_mlme_event(fidl_mlme::MlmeEvent::DeauthenticateInd {
1089 ind: fidl_mlme::DeauthenticateIndication {
1090 peer_sta_address: self.sta.bssid().to_array(),
1091 reason_code,
1092 locally_initiated: locally_initiated.0,
1093 },
1094 })
1095 .unwrap_or_else(|e| error!("error sending MLME-DEAUTHENTICATE.indication: {}", e));
1096 }
1097
1098 fn send_disassoc_ind(
1100 &mut self,
1101 reason_code: fidl_ieee80211::ReasonCode,
1102 locally_initiated: LocallyInitiated,
1103 ) {
1104 self.ctx
1105 .device
1106 .send_mlme_event(fidl_mlme::MlmeEvent::DisassociateInd {
1107 ind: fidl_mlme::DisassociateIndication {
1108 peer_sta_address: self.sta.bssid().to_array(),
1109 reason_code,
1110 locally_initiated: locally_initiated.0,
1111 },
1112 })
1113 .unwrap_or_else(|e| error!("error sending MLME-DISASSOCIATE.indication: {}", e));
1114 }
1115
1116 async fn clear_association(&mut self) -> Result<(), zx::Status> {
1117 self.ctx
1118 .device
1119 .clear_association(&fidl_softmac::WlanSoftmacBaseClearAssociationRequest {
1120 peer_addr: Some(self.sta.bssid().to_array()),
1121 ..Default::default()
1122 })
1123 .await
1124 }
1125
1126 fn forward_sae_frame_rx(
1128 &mut self,
1129 seq_num: u16,
1130 status_code: fidl_ieee80211::StatusCode,
1131 sae_fields: Vec<u8>,
1132 ) {
1133 self.ctx
1134 .device
1135 .send_mlme_event(fidl_mlme::MlmeEvent::OnSaeFrameRx {
1136 frame: fidl_mlme::SaeFrame {
1137 peer_sta_address: self.sta.bssid().to_array(),
1138 seq_num,
1139 status_code,
1140 sae_fields,
1141 },
1142 })
1143 .unwrap_or_else(|e| error!("error sending OnSaeFrameRx: {}", e));
1144 }
1145
1146 fn forward_sae_handshake_ind(&mut self) {
1147 self.ctx
1148 .device
1149 .send_mlme_event(fidl_mlme::MlmeEvent::OnSaeHandshakeInd {
1150 ind: fidl_mlme::SaeHandshakeIndication {
1151 peer_sta_address: self.sta.bssid().to_array(),
1152 },
1153 })
1154 .unwrap_or_else(|e| error!("error sending OnSaeHandshakeInd: {}", e));
1155 }
1156
1157 fn send_mgmt_or_ctrl_frame(&mut self, buffer: ArenaStaticBox<[u8]>) -> Result<(), zx::Status> {
1158 self.ctx.device.send_wlan_frame(buffer, fidl_softmac::WlanTxInfoFlags::empty(), None)
1159 }
1160}
1161
1162pub struct ParsedConnectRequest {
1163 pub selected_bss: BssDescription,
1164 pub connect_failure_timeout: u32,
1165 pub auth_type: fidl_mlme::AuthenticationTypes,
1166 pub sae_password: Vec<u8>,
1167 pub wep_key: Option<fidl_mlme::SetKeyDescriptor>,
1168 pub security_ie: Vec<u8>,
1169 pub owe_public_key: Option<fidl_internal::OwePublicKey>,
1170}
1171
1172pub struct ParsedAssociateResp {
1173 pub association_id: u16,
1174 pub capabilities: CapabilityInfo,
1175 pub rates: Vec<ie::SupportedRate>,
1176 pub ht_cap: Option<ie::HtCapabilities>,
1177 pub vht_cap: Option<ie::VhtCapabilities>,
1178}
1179
1180impl ParsedAssociateResp {
1181 pub fn parse<B: SplitByteSlice>(assoc_resp_frame: &mac::AssocRespFrame<B>) -> Self {
1182 let mut parsed = ParsedAssociateResp {
1183 association_id: assoc_resp_frame.assoc_resp_hdr.aid,
1184 capabilities: assoc_resp_frame.assoc_resp_hdr.capabilities,
1185 rates: vec![],
1186 ht_cap: None,
1187 vht_cap: None,
1188 };
1189 for (id, body) in assoc_resp_frame.ies() {
1190 match id {
1191 Id::SUPPORTED_RATES => match ie::parse_supported_rates(body) {
1192 Err(e) => warn!("invalid Supported Rates: {}", e),
1193 Ok(supported_rates) => {
1194 parsed.rates.extend(supported_rates.iter());
1196 }
1197 },
1198 Id::EXTENDED_SUPPORTED_RATES => match ie::parse_extended_supported_rates(body) {
1199 Err(e) => warn!("invalid Extended Supported Rates: {}", e),
1200 Ok(supported_rates) => {
1201 parsed.rates.extend(supported_rates.iter());
1203 }
1204 },
1205 Id::HT_CAPABILITIES => match ie::parse_ht_capabilities(body) {
1206 Err(e) => warn!("invalid HT Capabilities: {}", e),
1207 Ok(ht_cap) => {
1208 parsed.ht_cap = Some(*ht_cap);
1209 }
1210 },
1211 Id::VHT_CAPABILITIES => match ie::parse_vht_capabilities(body) {
1212 Err(e) => warn!("invalid VHT Capabilities: {}", e),
1213 Ok(vht_cap) => {
1214 parsed.vht_cap = Some(*vht_cap);
1215 }
1216 },
1217 _ => {}
1219 }
1220 }
1221 parsed
1222 }
1223}
1224
1225impl<'a, D: DeviceOps> BlockAckTx for BoundClient<'a, D> {
1226 fn send_block_ack_frame(&mut self, n: usize, body: &[u8]) -> Result<(), Error> {
1230 let arena = Arena::new();
1231 let buffer = arena.insert_default_slice::<u8>(n);
1232 let mut buffer = arena.make_static(buffer);
1233 let mut writer = BufferWriter::new(&mut buffer[..]);
1234 write_block_ack_hdr(
1235 &mut writer,
1236 self.sta.bssid(),
1237 self.sta.iface_mac,
1238 &mut self.ctx.seq_mgr,
1239 )
1240 .and_then(|_| writer.append_bytes(body).map_err(Into::into))?;
1241 self.send_mgmt_or_ctrl_frame(buffer)
1242 .map_err(|status| Error::Status(format!("error sending BlockAck frame"), status))
1243 }
1244}
1245
1246fn write_block_ack_hdr<B: Append>(
1251 buffer: &mut B,
1252 bssid: Bssid,
1253 addr: MacAddr,
1254 seq_mgr: &mut SequenceManager,
1255) -> Result<(), Error> {
1256 Ok(append_frame_to!(
1260 buffer,
1261 {
1262 headers: {
1263 mac::MgmtHdr: &mgmt_writer::mgmt_hdr_to_ap(
1264 mac::FrameControl(0)
1265 .with_frame_type(mac::FrameType::MGMT)
1266 .with_mgmt_subtype(mac::MgmtSubtype::ACTION),
1267 bssid,
1268 addr,
1269 mac::SequenceControl(0)
1270 .with_seq_num(seq_mgr.next_sns1(&bssid.into()) as u16),
1271 ),
1272 },
1273 }
1274 )
1275 .map(|_buffer| {})?)
1276}
1277
1278#[cfg(test)]
1279mod tests {
1280 use super::state::DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT;
1281 use super::*;
1282 use crate::block_ack::{
1283 self, ADDBA_REQ_FRAME_LEN, ADDBA_RESP_FRAME_LEN, BlockAckState, Closed,
1284 };
1285 use crate::client::lost_bss::LostBssCounter;
1286 use crate::client::test_utils::drain_timeouts;
1287 use crate::device::{FakeDevice, FakeDeviceConfig, FakeDeviceState, LinkStatus, test_utils};
1288 use crate::test_utils::{MockWlanRxInfo, fake_wlan_channel};
1289 use assert_matches::assert_matches;
1290 use fidl_fuchsia_wlan_common as fidl_common;
1291 use fidl_fuchsia_wlan_internal as fidl_internal;
1292 use fuchsia_sync::Mutex;
1293 use std::sync::{Arc, LazyLock};
1294 use wlan_common::capabilities::StaCapabilities;
1295 use wlan_common::channel::Cbw;
1296 use wlan_common::stats::SignalStrengthAverage;
1297 use wlan_common::test_utils::fake_capabilities::fake_client_capabilities;
1298 use wlan_common::test_utils::fake_frames::*;
1299 use wlan_common::timer::{self, create_timer};
1300 use wlan_common::{fake_bss_description, fake_fidl_bss_description};
1301 use wlan_sme::responder::Responder;
1302 use wlan_statemachine::*;
1303 static BSSID: LazyLock<Bssid> = LazyLock::new(|| [6u8; 6].into());
1304 static IFACE_MAC: LazyLock<MacAddr> = LazyLock::new(|| [7u8; 6].into());
1305 const RSNE: &[u8] = &[
1306 0x30, 0x14, 1, 0, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x02, 0xa8, 0x04, ];
1315 const SCAN_CHANNEL_PRIMARY: u8 = 6;
1316 #[rustfmt::skip]
1318 const BEACON_FRAME: &'static [u8] = &[
1319 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, ];
1336
1337 struct MockObjects {
1338 fake_device: FakeDevice,
1339 fake_device_state: Arc<Mutex<FakeDeviceState>>,
1340 timer: Option<Timer<super::TimedEvent>>,
1341 time_stream: timer::EventStream<super::TimedEvent>,
1342 }
1343
1344 impl MockObjects {
1345 async fn new() -> Self {
1349 let (timer, time_stream) = create_timer();
1350 let (fake_device, fake_device_state) = FakeDevice::new_with_config(
1351 FakeDeviceConfig::default()
1352 .with_mock_mac_role(fidl_common::WlanMacRole::Client)
1353 .with_mock_sta_addr((*IFACE_MAC).to_array()),
1354 )
1355 .await;
1356 Self { fake_device, fake_device_state, timer: Some(timer), time_stream }
1357 }
1358
1359 async fn make_mlme(&mut self) -> ClientMlme<FakeDevice> {
1360 let mut mlme = ClientMlme::new(
1361 Default::default(),
1362 self.fake_device.clone(),
1363 self.timer.take().unwrap(),
1364 )
1365 .await
1366 .expect("Failed to create client MLME.");
1367 mlme.set_main_channel(fake_wlan_channel().into())
1368 .await
1369 .expect("unable to set main channel");
1370 mlme
1371 }
1372 }
1373
1374 fn scan_req() -> fidl_mlme::ScanRequest {
1375 fidl_mlme::ScanRequest {
1376 txn_id: 1337,
1377 scan_type: fidl_mlme::ScanTypes::Passive,
1378 channel_list: vec![SCAN_CHANNEL_PRIMARY],
1379 ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
1380 probe_delay: 0,
1381 min_channel_time: 100,
1382 max_channel_time: 300,
1383 }
1384 }
1385
1386 fn make_client_station() -> Client {
1387 let connect_req = ParsedConnectRequest {
1388 selected_bss: fake_bss_description!(Open, bssid: BSSID.to_array()),
1389 connect_failure_timeout: 100,
1390 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1391 sae_password: vec![],
1392 wep_key: None,
1393 security_ie: vec![],
1394 owe_public_key: None,
1395 };
1396 Client::new(connect_req, *IFACE_MAC, fake_client_capabilities())
1397 }
1398
1399 fn make_client_station_protected() -> Client {
1400 let connect_req = ParsedConnectRequest {
1401 selected_bss: fake_bss_description!(Wpa2, bssid: BSSID.to_array()),
1402 connect_failure_timeout: 100,
1403 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1404 sae_password: vec![],
1405 wep_key: None,
1406 security_ie: RSNE.to_vec(),
1407 owe_public_key: None,
1408 };
1409 Client::new(connect_req, *IFACE_MAC, fake_client_capabilities())
1410 }
1411
1412 impl ClientMlme<FakeDevice> {
1413 fn make_client_station(&mut self) {
1414 self.sta.replace(make_client_station());
1415 }
1416
1417 fn make_client_station_protected(&mut self) {
1418 self.sta.replace(make_client_station_protected());
1419 }
1420
1421 fn get_bound_client(&mut self) -> Option<BoundClient<'_, FakeDevice>> {
1422 match self.sta.as_mut() {
1423 None => None,
1424 Some(sta) => {
1425 Some(sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state))
1426 }
1427 }
1428 }
1429 }
1430
1431 impl BoundClient<'_, FakeDevice> {
1432 fn move_to_associated_state(&mut self) {
1433 use super::state::*;
1434 let status_check_timeout =
1435 schedule_association_status_timeout(self.sta.beacon_period(), &mut self.ctx.timer);
1436 let state =
1437 States::from(wlan_statemachine::testing::new_state(Associated(Association {
1438 aid: 42,
1439 assoc_resp_ies: vec![],
1440 controlled_port_open: true,
1441 ap_ht_op: None,
1442 ap_vht_op: None,
1443 qos: Qos::Disabled,
1444 lost_bss_counter: LostBssCounter::start(
1445 self.sta.beacon_period(),
1446 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
1447 ),
1448 status_check_timeout,
1449 signal_strength_average: SignalStrengthAverage::new(),
1450 block_ack_state: StateMachine::new(BlockAckState::from(State::new(Closed))),
1451 })));
1452 self.sta.state.replace(state);
1453 }
1454
1455 async fn close_controlled_port(&mut self) {
1456 self.handle_mlme_req(wlan_sme::MlmeRequest::SetCtrlPort(
1457 fidl_mlme::SetControlledPortRequest {
1458 peer_sta_address: BSSID.to_array(),
1459 state: fidl_mlme::ControlledPortState::Closed,
1460 },
1461 ))
1462 .await;
1463 }
1464 }
1465
1466 #[fuchsia::test(allow_stalls = false)]
1467 async fn spawns_new_sta_on_connect_request_from_sme() {
1468 let mut m = MockObjects::new().await;
1469 let mut me = m.make_mlme().await;
1470 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1471 me.on_sme_connect(fidl_mlme::ConnectRequest {
1472 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
1473 connect_failure_timeout: 100,
1474 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1475 sae_password: vec![],
1476 wep_key: None,
1477 security_ie: vec![],
1478 owe_public_key: None,
1479 })
1480 .await
1481 .expect("valid ConnectRequest should be handled successfully");
1482 me.get_bound_client().expect("client sta should have been created by now.");
1483 }
1484
1485 #[fuchsia::test(allow_stalls = false)]
1486 async fn fails_to_connect_if_channel_unknown() {
1487 let mut m = MockObjects::new().await;
1488 let mut me = m.make_mlme().await;
1489 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1490 let mut req = fidl_mlme::ConnectRequest {
1491 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
1492 connect_failure_timeout: 100,
1493 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1494 sae_password: vec![],
1495 wep_key: None,
1496 security_ie: vec![],
1497 owe_public_key: None,
1498 };
1499
1500 req.selected_bss.channel.cbw = fidl_fuchsia_wlan_ieee80211::ChannelBandwidth::unknown();
1501 me.on_sme_connect(req)
1502 .await
1503 .expect_err("ConnectRequest with unknown channel should be rejected");
1504 assert!(me.get_bound_client().is_none());
1505 }
1506
1507 #[fuchsia::test(allow_stalls = false)]
1508 async fn rsn_ie_implies_sta_eapol_required() {
1509 let mut m = MockObjects::new().await;
1510 let mut me = m.make_mlme().await;
1511 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1512 me.on_sme_connect(fidl_mlme::ConnectRequest {
1513 selected_bss: fake_fidl_bss_description!(Wpa2, ssid: Ssid::try_from("foo").unwrap()),
1514 connect_failure_timeout: 100,
1515 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1516 sae_password: vec![],
1517 wep_key: None,
1518 security_ie: vec![],
1519 owe_public_key: None,
1520 })
1521 .await
1522 .expect("valid ConnectRequest should be handled successfully");
1523 let client = me.get_bound_client().expect("client sta should have been created by now.");
1524 assert!(client.sta.eapol_required());
1525 }
1526
1527 #[fuchsia::test(allow_stalls = false)]
1528 async fn wpa1_implies_sta_eapol_required() {
1529 let mut m = MockObjects::new().await;
1530 let mut me = m.make_mlme().await;
1531 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1532 me.on_sme_connect(fidl_mlme::ConnectRequest {
1533 selected_bss: fake_fidl_bss_description!(Wpa1, ssid: Ssid::try_from("foo").unwrap()),
1534 connect_failure_timeout: 100,
1535 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1536 sae_password: vec![],
1537 wep_key: None,
1538 security_ie: vec![],
1539 owe_public_key: None,
1540 })
1541 .await
1542 .expect("valid ConnectRequest should be handled successfully");
1543 let client = me.get_bound_client().expect("client sta should have been created by now.");
1544 assert!(client.sta.eapol_required());
1545 }
1546
1547 #[fuchsia::test(allow_stalls = false)]
1548 async fn no_wpa_or_rsn_ie_implies_sta_eapol_not_required() {
1549 let mut m = MockObjects::new().await;
1550 let mut me = m.make_mlme().await;
1551 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1552 me.on_sme_connect(fidl_mlme::ConnectRequest {
1553 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
1554 connect_failure_timeout: 100,
1555 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1556 sae_password: vec![],
1557 wep_key: None,
1558 security_ie: vec![],
1559 owe_public_key: None,
1560 })
1561 .await
1562 .expect("valid ConnectRequest should be handled successfully");
1563 let client = me.get_bound_client().expect("client sta should have been created by now.");
1564 assert!(!client.sta.eapol_required());
1565 }
1566
1567 async fn handle_association_status_checks_and_signal_reports(
1577 mock_objects: &mut MockObjects,
1578 mlme: &mut ClientMlme<FakeDevice>,
1579 beacon_count: u32,
1580 ) {
1581 for _ in 0..beacon_count / super::state::ASSOCIATION_STATUS_TIMEOUT_BEACON_COUNT {
1582 let (_, timed_event, _) = mock_objects
1583 .time_stream
1584 .try_next()
1585 .unwrap()
1586 .expect("Should have scheduled a timed event");
1587 mlme.handle_timed_event(timed_event.event).await;
1588 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 0);
1589 mock_objects
1590 .fake_device_state
1591 .lock()
1592 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
1593 .expect("error reading SignalReport.indication");
1594 }
1595 }
1596
1597 #[fuchsia::test(allow_stalls = false)]
1598 async fn test_auto_deauth_uninterrupted_interval() {
1599 let mut mock_objects = MockObjects::new().await;
1600 let mut mlme = mock_objects.make_mlme().await;
1601 mlme.make_client_station();
1602 let mut client = mlme.get_bound_client().expect("client should be present");
1603
1604 client.move_to_associated_state();
1605
1606 handle_association_status_checks_and_signal_reports(
1608 &mut mock_objects,
1609 &mut mlme,
1610 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
1611 )
1612 .await;
1613
1614 let (_, timed_event, _) = mock_objects
1616 .time_stream
1617 .try_next()
1618 .unwrap()
1619 .expect("Should have scheduled a timed event");
1620
1621 mlme.handle_timed_event(timed_event.event).await;
1623 mock_objects
1624 .fake_device_state
1625 .lock()
1626 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
1627 .expect("error reading SignalReport.indication");
1628 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
1629 #[rustfmt::skip]
1630 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
1631 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, ][..]);
1640 let deauth_ind = mock_objects
1641 .fake_device_state
1642 .lock()
1643 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
1644 .expect("error reading DEAUTHENTICATE.indication");
1645 assert_eq!(
1646 deauth_ind,
1647 fidl_mlme::DeauthenticateIndication {
1648 peer_sta_address: BSSID.to_array(),
1649 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
1650 locally_initiated: true,
1651 }
1652 );
1653 }
1654
1655 #[fuchsia::test(allow_stalls = false)]
1656 async fn test_auto_deauth_received_beacon() {
1657 let mut mock_objects = MockObjects::new().await;
1658 let mut mlme = mock_objects.make_mlme().await;
1659 mlme.make_client_station();
1660 let mut client = mlme.get_bound_client().expect("client should be present");
1661
1662 client.move_to_associated_state();
1663
1664 handle_association_status_checks_and_signal_reports(
1666 &mut mock_objects,
1667 &mut mlme,
1668 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
1669 )
1670 .await;
1671
1672 mlme.on_mac_frame_rx(
1675 BEACON_FRAME,
1676 fidl_softmac::WlanRxInfo {
1677 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
1678 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
1679 phy: fidl_ieee80211::WlanPhyType::Dsss,
1680 data_rate: 0,
1681 channel: mlme.channel_state.get_main_channel().unwrap(),
1682 mcs: 0,
1683 rssi_dbm: 0,
1684 snr_dbh: 0,
1685 },
1686 0.into(),
1687 )
1688 .await;
1689
1690 handle_association_status_checks_and_signal_reports(
1692 &mut mock_objects,
1693 &mut mlme,
1694 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
1695 )
1696 .await;
1697
1698 let (_, timed_event2, _) = mock_objects
1700 .time_stream
1701 .try_next()
1702 .unwrap()
1703 .expect("Should have scheduled a timed event");
1704
1705 mlme.handle_timed_event(timed_event2.event).await;
1707 mock_objects
1708 .fake_device_state
1709 .lock()
1710 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
1711 .expect("error reading SignalReport.indication");
1712 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
1713 #[rustfmt::skip]
1714 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
1715 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, ][..]);
1724 let deauth_ind = mock_objects
1725 .fake_device_state
1726 .lock()
1727 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
1728 .expect("error reading DEAUTHENTICATE.indication");
1729 assert_eq!(
1730 deauth_ind,
1731 fidl_mlme::DeauthenticateIndication {
1732 peer_sta_address: BSSID.to_array(),
1733 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
1734 locally_initiated: true,
1735 }
1736 );
1737 }
1738
1739 #[fuchsia::test(allow_stalls = false)]
1740 async fn client_send_open_auth_frame() {
1741 let mut m = MockObjects::new().await;
1742 let mut me = m.make_mlme().await;
1743 me.make_client_station();
1744 let mut client = me.get_bound_client().expect("client should be present");
1745 client.send_open_auth_frame().expect("error delivering WLAN frame");
1746 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1747 #[rustfmt::skip]
1748 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1749 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, ][..]);
1761 }
1762
1763 #[fuchsia::test(allow_stalls = false)]
1764 async fn client_send_assoc_req_frame() {
1765 let mut m = MockObjects::new().await;
1766 let mut me = m.make_mlme().await;
1767 let connect_req = ParsedConnectRequest {
1768 selected_bss: fake_bss_description!(Wpa2,
1769 ssid: Ssid::try_from([11, 22, 33, 44]).unwrap(),
1770 bssid: BSSID.to_array(),
1771 ),
1772 connect_failure_timeout: 100,
1773 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1774 sae_password: vec![],
1775 wep_key: None,
1776 security_ie: RSNE.to_vec(),
1777 owe_public_key: None,
1778 };
1779 let client_capabilities = ClientCapabilities(StaCapabilities {
1780 capability_info: CapabilityInfo(0x1234),
1781 rates: vec![8u8, 7, 6, 5, 4, 3, 2, 1, 0].into_iter().map(ie::SupportedRate).collect(),
1782 ht_cap: ie::parse_ht_capabilities(&(0..26).collect::<Vec<u8>>()[..]).map(|h| *h).ok(),
1783 vht_cap: ie::parse_vht_capabilities(&(100..112).collect::<Vec<u8>>()[..])
1784 .map(|v| *v)
1785 .ok(),
1786 });
1787 me.sta.replace(Client::new(connect_req, *IFACE_MAC, client_capabilities));
1788 let mut client = me.get_bound_client().expect("client should be present");
1789 client.send_assoc_req_frame().expect("error delivering WLAN frame");
1790 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1791 assert_eq!(
1792 &m.fake_device_state.lock().wlan_queue[0].0[..],
1793 &[
1794 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, ][..]
1828 );
1829 }
1830
1831 #[fuchsia::test(allow_stalls = false)]
1832 async fn client_send_keep_alive_resp_frame() {
1833 let mut m = MockObjects::new().await;
1834 let mut me = m.make_mlme().await;
1835 me.make_client_station();
1836 let mut client = me.get_bound_client().expect("client should be present");
1837 client.send_keep_alive_resp_frame().expect("error delivering WLAN frame");
1838 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1839 #[rustfmt::skip]
1840 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1841 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, ][..]);
1849 }
1850
1851 #[fuchsia::test(allow_stalls = false)]
1852 async fn client_send_data_frame() {
1853 let payload = vec![5; 8];
1854 let mut m = MockObjects::new().await;
1855 let mut me = m.make_mlme().await;
1856 me.make_client_station();
1857 let mut client = me.get_bound_client().expect("client should be present");
1858 client
1859 .send_data_frame(*IFACE_MAC, [4; 6].into(), false, false, 0x1234, &payload[..], None)
1860 .expect("error delivering WLAN frame");
1861 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1862 #[rustfmt::skip]
1863 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1864 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,
1877 ][..]);
1878 }
1879
1880 #[fuchsia::test(allow_stalls = false)]
1881 async fn client_send_data_frame_ipv4_qos() {
1882 let mut m = MockObjects::new().await;
1883 let mut me = m.make_mlme().await;
1884 let mut client = make_client_station();
1885 client
1886 .bind(&mut me.ctx, &mut me.scanner, &mut me.channel_state)
1887 .send_data_frame(
1888 *IFACE_MAC,
1889 [4; 6].into(),
1890 false,
1891 true,
1892 0x0800, &[1, 0xB0, 3, 4, 5], None,
1895 )
1896 .expect("error delivering WLAN frame");
1897 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1898 #[rustfmt::skip]
1899 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1900 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,
1914 ][..]);
1915 }
1916
1917 #[fuchsia::test(allow_stalls = false)]
1918 async fn client_send_data_frame_ipv6_qos() {
1919 let mut m = MockObjects::new().await;
1920 let mut me = m.make_mlme().await;
1921 let mut client = make_client_station();
1922 client
1923 .bind(&mut me.ctx, &mut me.scanner, &mut me.channel_state)
1924 .send_data_frame(
1925 *IFACE_MAC,
1926 [4; 6].into(),
1927 false,
1928 true,
1929 0x86DD, &[0b0101, 0b10000000, 3, 4, 5], None,
1932 )
1933 .expect("error delivering WLAN frame");
1934 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1935 #[rustfmt::skip]
1936 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1937 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,
1951 ][..]);
1952 }
1953
1954 #[fuchsia::test(allow_stalls = false)]
1955 async fn client_send_data_frame_from_ds() {
1956 let payload = vec![5; 8];
1957 let mut m = MockObjects::new().await;
1958 let mut me = m.make_mlme().await;
1959 me.make_client_station();
1960 let mut client = me.get_bound_client().expect("client should be present");
1961 client
1962 .send_data_frame([3; 6].into(), [4; 6].into(), false, false, 0x1234, &payload[..], None)
1963 .expect("error delivering WLAN frame");
1964 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1965 #[rustfmt::skip]
1966 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1967 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,
1981 ][..]);
1982 }
1983
1984 #[fuchsia::test(allow_stalls = false)]
1985 async fn client_send_deauthentication_notification() {
1986 let mut m = MockObjects::new().await;
1987 let mut me = m.make_mlme().await;
1988 me.make_client_station();
1989 let mut client = me.get_bound_client().expect("client should be present");
1990
1991 client
1992 .send_deauth_frame(fidl_ieee80211::ReasonCode::ApInitiated.into())
1993 .expect("error delivering WLAN frame");
1994 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1995 #[rustfmt::skip]
1996 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1997 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, ][..]);
2006 }
2007
2008 fn mock_rx_info<'a>(client: &BoundClient<'a, FakeDevice>) -> fidl_softmac::WlanRxInfo {
2009 let channel = client.channel_state.get_main_channel().unwrap();
2010 MockWlanRxInfo::with_channel(channel).into()
2011 }
2012
2013 #[fuchsia::test(allow_stalls = false)]
2014 async fn respond_to_keep_alive_request() {
2015 #[rustfmt::skip]
2016 let data_frame = vec![
2017 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, ];
2025 let mut m = MockObjects::new().await;
2026 let mut me = m.make_mlme().await;
2027 me.make_client_station();
2028 let mut client = me.get_bound_client().expect("client should be present");
2029 client.move_to_associated_state();
2030
2031 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2032
2033 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2034 #[rustfmt::skip]
2035 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
2036 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, ][..]);
2044 }
2045
2046 #[fuchsia::test(allow_stalls = false)]
2047 async fn data_frame_to_ethernet_single_llc() {
2048 let mut data_frame = make_data_frame_single_llc(None, None);
2049 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;
2054 let mut me = m.make_mlme().await;
2055 me.make_client_station();
2056 let mut client = me.get_bound_client().expect("client should be present");
2057 client.move_to_associated_state();
2058
2059 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2060
2061 assert_eq!(m.fake_device_state.lock().eth_queue.len(), 1);
2062 #[rustfmt::skip]
2063 assert_eq!(m.fake_device_state.lock().eth_queue[0], [
2064 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 9, 10, 11, 11, 11, ]);
2069 }
2070
2071 #[fuchsia::test(allow_stalls = false)]
2072 async fn data_frame_to_ethernet_amsdu() {
2073 let mut data_frame = make_data_frame_amsdu();
2074 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;
2079 let mut me = m.make_mlme().await;
2080 me.make_client_station();
2081 let mut client = me.get_bound_client().expect("client should be present");
2082 client.move_to_associated_state();
2083
2084 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2085
2086 let queue = &m.fake_device_state.lock().eth_queue;
2087 assert_eq!(queue.len(), 2);
2088 #[rustfmt::skip]
2089 let mut expected_first_eth_frame = vec![
2090 0x78, 0x8a, 0x20, 0x0d, 0x67, 0x03, 0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xab, 0x08, 0x00, ];
2094 expected_first_eth_frame.extend_from_slice(MSDU_1_PAYLOAD);
2095 assert_eq!(queue[0], &expected_first_eth_frame[..]);
2096 #[rustfmt::skip]
2097 let mut expected_second_eth_frame = vec![
2098 0x78, 0x8a, 0x20, 0x0d, 0x67, 0x04, 0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xac, 0x08, 0x01, ];
2102 expected_second_eth_frame.extend_from_slice(MSDU_2_PAYLOAD);
2103 assert_eq!(queue[1], &expected_second_eth_frame[..]);
2104 }
2105
2106 #[fuchsia::test(allow_stalls = false)]
2107 async fn data_frame_to_ethernet_amsdu_padding_too_short() {
2108 let mut data_frame = make_data_frame_amsdu_padding_too_short();
2109 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;
2114 let mut me = m.make_mlme().await;
2115 me.make_client_station();
2116 let mut client = me.get_bound_client().expect("client should be present");
2117 client.move_to_associated_state();
2118
2119 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2120
2121 let queue = &m.fake_device_state.lock().eth_queue;
2122 assert_eq!(queue.len(), 1);
2123 #[rustfmt::skip]
2124 let mut expected_first_eth_frame = vec![
2125 0x78, 0x8a, 0x20, 0x0d, 0x67, 0x03, 0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xab, 0x08, 0x00, ];
2129 expected_first_eth_frame.extend_from_slice(MSDU_1_PAYLOAD);
2130 assert_eq!(queue[0], &expected_first_eth_frame[..]);
2131 }
2132
2133 #[fuchsia::test(allow_stalls = false)]
2134 async fn data_frame_controlled_port_closed() {
2135 let mut data_frame = make_data_frame_single_llc(None, None);
2136 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;
2141 let mut me = m.make_mlme().await;
2142 me.make_client_station_protected();
2143 let mut client = me.get_bound_client().expect("client should be present");
2144 client.move_to_associated_state();
2145 client.close_controlled_port().await;
2146
2147 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2148
2149 assert_eq!(m.fake_device_state.lock().eth_queue.len(), 0);
2151 }
2152
2153 #[fuchsia::test(allow_stalls = false)]
2154 async fn eapol_frame_controlled_port_closed() {
2155 let (src_addr, dst_addr, mut eapol_frame) = make_eapol_frame(*IFACE_MAC);
2156 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;
2161 let mut me = m.make_mlme().await;
2162 me.make_client_station_protected();
2163 let mut client = me.get_bound_client().expect("client should be present");
2164 client.move_to_associated_state();
2165 client.close_controlled_port().await;
2166
2167 client.on_mac_frame(&eapol_frame[..], mock_rx_info(&client), 0.into()).await;
2168
2169 assert_eq!(m.fake_device_state.lock().eth_queue.len(), 0);
2171
2172 let eapol_ind = m
2174 .fake_device_state
2175 .lock()
2176 .next_mlme_msg::<fidl_mlme::EapolIndication>()
2177 .expect("error reading EAPOL.indication");
2178 assert_eq!(
2179 eapol_ind,
2180 fidl_mlme::EapolIndication {
2181 src_addr: src_addr.to_array(),
2182 dst_addr: dst_addr.to_array(),
2183 data: EAPOL_PDU.to_vec()
2184 }
2185 );
2186 }
2187
2188 #[fuchsia::test(allow_stalls = false)]
2189 async fn eapol_frame_is_controlled_port_open() {
2190 let (src_addr, dst_addr, mut eapol_frame) = make_eapol_frame(*IFACE_MAC);
2191 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;
2196 let mut me = m.make_mlme().await;
2197 me.make_client_station();
2198 let mut client = me.get_bound_client().expect("client should be present");
2199 client.move_to_associated_state();
2200
2201 client.on_mac_frame(&eapol_frame[..], mock_rx_info(&client), 0.into()).await;
2202
2203 assert_eq!(m.fake_device_state.lock().eth_queue.len(), 0);
2205
2206 let eapol_ind = m
2208 .fake_device_state
2209 .lock()
2210 .next_mlme_msg::<fidl_mlme::EapolIndication>()
2211 .expect("error reading EAPOL.indication");
2212 assert_eq!(
2213 eapol_ind,
2214 fidl_mlme::EapolIndication {
2215 src_addr: src_addr.to_array(),
2216 dst_addr: dst_addr.to_array(),
2217 data: EAPOL_PDU.to_vec()
2218 }
2219 );
2220 }
2221
2222 #[fuchsia::test(allow_stalls = false)]
2223 async fn send_eapol_ind_success() {
2224 let mut m = MockObjects::new().await;
2225 let mut me = m.make_mlme().await;
2226 me.make_client_station();
2227 let mut client = me.get_bound_client().expect("client should be present");
2228 client
2229 .send_eapol_indication([1; 6].into(), [2; 6].into(), &[5; 200])
2230 .expect("expected EAPOL.indication to be sent");
2231 let eapol_ind = m
2232 .fake_device_state
2233 .lock()
2234 .next_mlme_msg::<fidl_mlme::EapolIndication>()
2235 .expect("error reading EAPOL.indication");
2236 assert_eq!(
2237 eapol_ind,
2238 fidl_mlme::EapolIndication {
2239 src_addr: [1; 6].into(),
2240 dst_addr: [2; 6].into(),
2241 data: vec![5; 200]
2242 }
2243 );
2244 }
2245
2246 #[fuchsia::test(allow_stalls = false)]
2247 async fn send_eapol_frame_success() {
2248 let mut m = MockObjects::new().await;
2249 let mut me = m.make_mlme().await;
2250 me.make_client_station();
2251 let mut client = me.get_bound_client().expect("client should be present");
2252 client.send_eapol_frame(*IFACE_MAC, (*BSSID).into(), false, &[5; 8]);
2253
2254 let eapol_confirm = m
2256 .fake_device_state
2257 .lock()
2258 .next_mlme_msg::<fidl_mlme::EapolConfirm>()
2259 .expect("error reading EAPOL.confirm");
2260 assert_eq!(
2261 eapol_confirm,
2262 fidl_mlme::EapolConfirm {
2263 result_code: fidl_mlme::EapolResultCode::Success,
2264 dst_addr: BSSID.to_array(),
2265 }
2266 );
2267
2268 #[rustfmt::skip]
2270 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
2271 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,
2284 ][..]);
2285 }
2286
2287 #[fuchsia::test(allow_stalls = false)]
2288 async fn send_eapol_frame_failure() {
2289 let mut m = MockObjects::new().await;
2290 m.fake_device_state.lock().config.send_wlan_frame_fails = true;
2291 let mut me = m.make_mlme().await;
2292 me.make_client_station();
2293 let mut client = me.get_bound_client().expect("client should be present");
2294 client.send_eapol_frame([1; 6].into(), [2; 6].into(), false, &[5; 200]);
2295
2296 let eapol_confirm = m
2298 .fake_device_state
2299 .lock()
2300 .next_mlme_msg::<fidl_mlme::EapolConfirm>()
2301 .expect("error reading EAPOL.confirm");
2302 assert_eq!(
2303 eapol_confirm,
2304 fidl_mlme::EapolConfirm {
2305 result_code: fidl_mlme::EapolResultCode::TransmissionFailure,
2306 dst_addr: [2; 6].into(),
2307 }
2308 );
2309
2310 assert!(m.fake_device_state.lock().wlan_queue.is_empty());
2312 }
2313
2314 #[fuchsia::test(allow_stalls = false)]
2315 async fn send_keys() {
2316 let mut m = MockObjects::new().await;
2317 let mut me = m.make_mlme().await;
2318 me.make_client_station_protected();
2319 let mut client = me.get_bound_client().expect("client should be present");
2320 client.move_to_associated_state();
2321
2322 assert!(m.fake_device_state.lock().keys.is_empty());
2323 client.handle_mlme_req(crate::test_utils::fake_set_keys_req((*BSSID).into())).await;
2324 assert_eq!(m.fake_device_state.lock().keys.len(), 1);
2325
2326 let sent_key = crate::test_utils::fake_key((*BSSID).into());
2327 let received_key = &m.fake_device_state.lock().keys[0];
2328 assert_eq!(received_key.key, Some(sent_key.key));
2329 assert_eq!(received_key.key_idx, Some(sent_key.key_id as u8));
2330 assert_eq!(received_key.key_type, Some(fidl_ieee80211::KeyType::Pairwise));
2331 }
2332
2333 #[fuchsia::test(allow_stalls = false)]
2334 async fn send_addba_req_frame() {
2335 let mut mock = MockObjects::new().await;
2336 let mut mlme = mock.make_mlme().await;
2337 mlme.make_client_station();
2338 let mut client = mlme.get_bound_client().expect("client should be present");
2339
2340 let mut body = [0u8; 16];
2341 let mut writer = BufferWriter::new(&mut body[..]);
2342 block_ack::write_addba_req_body(&mut writer, 1).expect("failed writing addba frame");
2343 client
2344 .send_block_ack_frame(ADDBA_REQ_FRAME_LEN, writer.into_written())
2345 .expect("failed sending addba frame");
2346 assert_eq!(
2347 &mock.fake_device_state.lock().wlan_queue[0].0[..],
2348 &[
2349 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, ][..]
2364 );
2365 }
2366
2367 #[fuchsia::test(allow_stalls = false)]
2368 async fn send_addba_resp_frame() {
2369 let mut mock = MockObjects::new().await;
2370 let mut mlme = mock.make_mlme().await;
2371 mlme.make_client_station();
2372 let mut client = mlme.get_bound_client().expect("client should be present");
2373
2374 let mut body = [0u8; 16];
2375 let mut writer = BufferWriter::new(&mut body[..]);
2376 block_ack::write_addba_resp_body(&mut writer, 1).expect("failed writing addba frame");
2377 client
2378 .send_block_ack_frame(ADDBA_RESP_FRAME_LEN, writer.into_written())
2379 .expect("failed sending addba frame");
2380 assert_eq!(
2381 &mock.fake_device_state.lock().wlan_queue[0].0[..],
2382 &[
2383 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, ][..]
2398 );
2399 }
2400
2401 #[fuchsia::test(allow_stalls = false)]
2402 async fn client_send_successful_connect_conf() {
2403 let mut m = MockObjects::new().await;
2404 let mut me = m.make_mlme().await;
2405 me.make_client_station();
2406 let mut client = me.get_bound_client().expect("client should be present");
2407
2408 client.send_connect_conf_success(42, &[0, 5, 3, 4, 5, 6, 7][..]);
2409 let connect_conf = m
2410 .fake_device_state
2411 .lock()
2412 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
2413 .expect("error reading Connect.confirm");
2414 assert_eq!(
2415 connect_conf,
2416 fidl_mlme::ConnectConfirm {
2417 peer_sta_address: BSSID.to_array(),
2418 result_code: fidl_ieee80211::StatusCode::Success,
2419 association_id: 42,
2420 association_ies: vec![0, 5, 3, 4, 5, 6, 7],
2421 }
2422 );
2423 }
2424
2425 #[fuchsia::test(allow_stalls = false)]
2426 async fn client_send_failed_connect_conf() {
2427 let mut m = MockObjects::new().await;
2428 let mut me = m.make_mlme().await;
2429 me.make_client_station();
2430 let mut client = me.get_bound_client().expect("client should be present");
2431 client.send_connect_conf_failure(fidl_ieee80211::StatusCode::DeniedNoMoreStas);
2432 let connect_conf = m
2433 .fake_device_state
2434 .lock()
2435 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
2436 .expect("error reading Connect.confirm");
2437 assert_eq!(
2438 connect_conf,
2439 fidl_mlme::ConnectConfirm {
2440 peer_sta_address: BSSID.to_array(),
2441 result_code: fidl_ieee80211::StatusCode::DeniedNoMoreStas,
2442 association_id: 0,
2443 association_ies: vec![],
2444 }
2445 );
2446 }
2447
2448 #[fuchsia::test(allow_stalls = false)]
2449 async fn client_send_scan_end_on_mlme_scan_busy() {
2450 let mut m = MockObjects::new().await;
2451 let mut me = m.make_mlme().await;
2452 me.make_client_station();
2453
2454 me.on_sme_scan(scan_req()).await;
2456 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
2457
2458 let scan_end = m
2459 .fake_device_state
2460 .lock()
2461 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2462 .expect("error reading MLME ScanEnd");
2463 assert_eq!(
2464 scan_end,
2465 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
2466 );
2467 }
2468
2469 #[fuchsia::test(allow_stalls = false)]
2470 async fn client_send_scan_end_on_scan_busy() {
2471 let mut m = MockObjects::new().await;
2472 let mut me = m.make_mlme().await;
2473 me.make_client_station();
2474
2475 me.on_sme_scan(scan_req()).await;
2477 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
2478
2479 let scan_end = m
2480 .fake_device_state
2481 .lock()
2482 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2483 .expect("error reading MLME ScanEnd");
2484 assert_eq!(
2485 scan_end,
2486 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
2487 );
2488 }
2489
2490 #[fuchsia::test(allow_stalls = false)]
2491 async fn client_send_scan_end_on_mlme_scan_invalid_args() {
2492 let mut m = MockObjects::new().await;
2493 let mut me = m.make_mlme().await;
2494
2495 me.make_client_station();
2496 me.on_sme_scan(fidl_mlme::ScanRequest {
2497 txn_id: 1337,
2498 scan_type: fidl_mlme::ScanTypes::Passive,
2499 channel_list: vec![], ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
2501 probe_delay: 0,
2502 min_channel_time: 100,
2503 max_channel_time: 300,
2504 })
2505 .await;
2506 let scan_end = m
2507 .fake_device_state
2508 .lock()
2509 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2510 .expect("error reading MLME ScanEnd");
2511 assert_eq!(
2512 scan_end,
2513 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
2514 );
2515 }
2516
2517 #[fuchsia::test(allow_stalls = false)]
2518 async fn client_send_scan_end_on_scan_invalid_args() {
2519 let mut m = MockObjects::new().await;
2520 let mut me = m.make_mlme().await;
2521
2522 me.make_client_station();
2523 me.on_sme_scan(fidl_mlme::ScanRequest {
2524 txn_id: 1337,
2525 scan_type: fidl_mlme::ScanTypes::Passive,
2526 channel_list: vec![6],
2527 ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
2528 probe_delay: 0,
2529 min_channel_time: 300, max_channel_time: 100,
2531 })
2532 .await;
2533 let scan_end = m
2534 .fake_device_state
2535 .lock()
2536 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2537 .expect("error reading MLME ScanEnd");
2538 assert_eq!(
2539 scan_end,
2540 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
2541 );
2542 }
2543
2544 #[fuchsia::test(allow_stalls = false)]
2545 async fn client_send_scan_end_on_passive_scan_fails() {
2546 let mut m = MockObjects::new().await;
2547 m.fake_device_state.lock().config.start_passive_scan_fails = true;
2548 let mut me = m.make_mlme().await;
2549
2550 me.make_client_station();
2551 me.on_sme_scan(scan_req()).await;
2552 let scan_end = m
2553 .fake_device_state
2554 .lock()
2555 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2556 .expect("error reading MLME ScanEnd");
2557 assert_eq!(
2558 scan_end,
2559 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::NotSupported }
2560 );
2561 }
2562
2563 #[fuchsia::test(allow_stalls = false)]
2564 async fn mlme_respond_to_query_device_info() {
2565 let mut mock_objects = MockObjects::new().await;
2566 let mut mlme = mock_objects.make_mlme().await;
2567
2568 let (responder, receiver) = Responder::new();
2569 mlme.handle_mlme_req(wlan_sme::MlmeRequest::QueryDeviceInfo(responder))
2570 .await
2571 .expect("Failed to send MlmeRequest::Connect");
2572 assert_eq!(
2573 receiver.await.unwrap(),
2574 fidl_mlme::DeviceInfo {
2575 sta_addr: IFACE_MAC.to_array(),
2576 factory_addr: IFACE_MAC.to_array(),
2577 role: fidl_common::WlanMacRole::Client,
2578 bands: test_utils::fake_mlme_band_caps(),
2579 softmac_hardware_capability: 0,
2580 qos_capable: false,
2581 }
2582 );
2583 }
2584
2585 #[fuchsia::test(allow_stalls = false)]
2586 async fn mlme_respond_to_query_mac_sublayer_support() {
2587 let mut m = MockObjects::new().await;
2588 let mut me = m.make_mlme().await;
2589
2590 let (responder, receiver) = Responder::new();
2591 me.handle_mlme_req(wlan_sme::MlmeRequest::QueryMacSublayerSupport(responder))
2592 .await
2593 .expect("Failed to send MlmeRequest::Connect");
2594 let resp = receiver.await.unwrap();
2595 assert_eq!(resp.rate_selection_offload.unwrap().supported, Some(false));
2596 assert_eq!(
2597 resp.data_plane.unwrap().data_plane_type,
2598 Some(fidl_common::DataPlaneType::EthernetDevice)
2599 );
2600 assert_eq!(resp.device.as_ref().unwrap().is_synthetic, Some(true));
2601 assert_eq!(
2602 resp.device.as_ref().unwrap().mac_implementation_type,
2603 Some(fidl_common::MacImplementationType::Softmac)
2604 );
2605 assert_eq!(resp.device.unwrap().tx_status_report_supported, Some(true));
2606 }
2607
2608 #[fuchsia::test(allow_stalls = false)]
2609 async fn mlme_respond_to_query_security_support() {
2610 let mut m = MockObjects::new().await;
2611 let mut me = m.make_mlme().await;
2612
2613 let (responder, receiver) = Responder::new();
2614 assert_matches!(
2615 me.handle_mlme_req(wlan_sme::MlmeRequest::QuerySecuritySupport(responder)).await,
2616 Ok(())
2617 );
2618 let resp = receiver.await.unwrap();
2619 assert_eq!(resp.mfp.unwrap().supported, Some(false));
2620 assert_eq!(resp.sae.as_ref().unwrap().driver_handler_supported, Some(false));
2621 assert_eq!(resp.sae.unwrap().sme_handler_supported, Some(false));
2622 }
2623
2624 #[fuchsia::test(allow_stalls = false)]
2625 async fn mlme_respond_to_query_spectrum_management_support() {
2626 let mut m = MockObjects::new().await;
2627 let mut me = m.make_mlme().await;
2628
2629 let (responder, receiver) = Responder::new();
2630 me.handle_mlme_req(wlan_sme::MlmeRequest::QuerySpectrumManagementSupport(responder))
2631 .await
2632 .expect("Failed to send MlmeRequest::QuerySpectrumManagementSupport");
2633 assert_eq!(receiver.await.unwrap().dfs.unwrap().supported, Some(true));
2634 }
2635
2636 #[fuchsia::test(allow_stalls = false)]
2637 async fn mlme_connect_unprotected_happy_path() {
2638 let mut m = MockObjects::new().await;
2639 let mut me = m.make_mlme().await;
2640 let channel = Channel::new(6, Cbw::Cbw40);
2641 let connect_req = fidl_mlme::ConnectRequest {
2642 selected_bss: fake_fidl_bss_description!(Open,
2643 ssid: Ssid::try_from("ssid").unwrap().into(),
2644 bssid: BSSID.to_array(),
2645 channel: channel.clone(),
2646 ),
2647 connect_failure_timeout: 100,
2648 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
2649 sae_password: vec![],
2650 wep_key: None,
2651 security_ie: vec![],
2652 owe_public_key: None,
2653 };
2654 me.handle_mlme_req(wlan_sme::MlmeRequest::Connect(connect_req))
2655 .await
2656 .expect("Failed to send MlmeRequest::Connect");
2657
2658 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
2660 assert_eq!(ids.len(), 1);
2661 });
2662
2663 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2665 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2666 #[rustfmt::skip]
2667 let expected = vec![
2668 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, ];
2680 assert_eq!(&frame[..], &expected[..]);
2681
2682 #[rustfmt::skip]
2684 let auth_resp_success = vec![
2685 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, ];
2697 me.on_mac_frame_rx(
2698 &auth_resp_success[..],
2699 MockWlanRxInfo::with_channel(channel.into()).into(),
2700 0.into(),
2701 )
2702 .await;
2703
2704 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2706 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2707 #[rustfmt::skip]
2708 let expected = vec![
2709 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, ];
2731 assert_eq!(&frame[..], &expected[..]);
2732
2733 #[rustfmt::skip]
2735 let assoc_resp_success = vec![
2736 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,
2750 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2754 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ];
2758 me.on_mac_frame_rx(
2759 &assoc_resp_success[..],
2760 MockWlanRxInfo::with_channel(channel.into()).into(),
2761 0.into(),
2762 )
2763 .await;
2764
2765 let msg = m
2767 .fake_device_state
2768 .lock()
2769 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
2770 .expect("expect ConnectConf");
2771 assert_eq!(
2772 msg,
2773 fidl_mlme::ConnectConfirm {
2774 peer_sta_address: BSSID.to_array(),
2775 result_code: fidl_ieee80211::StatusCode::Success,
2776 association_id: 42,
2777 association_ies: vec![
2778 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
2781 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2785 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
2789 }
2790 );
2791
2792 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
2794 }
2795
2796 #[fuchsia::test(allow_stalls = false)]
2797 async fn mlme_connect_protected_happy_path() {
2798 let mut m = MockObjects::new().await;
2799 let mut me = m.make_mlme().await;
2800 let channel = Channel::new(6, Cbw::Cbw40);
2801 let connect_req = fidl_mlme::ConnectRequest {
2802 selected_bss: fake_fidl_bss_description!(Wpa2,
2803 ssid: Ssid::try_from("ssid").unwrap().into(),
2804 bssid: BSSID.to_array(),
2805 channel: channel.clone(),
2806 ),
2807 connect_failure_timeout: 100,
2808 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
2809 sae_password: vec![],
2810 wep_key: None,
2811 security_ie: vec![
2812 48, 18, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 2, ],
2818 owe_public_key: None,
2819 };
2820 me.handle_mlme_req(wlan_sme::MlmeRequest::Connect(connect_req))
2821 .await
2822 .expect("Failed to send MlmeRequest::Connect");
2823
2824 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
2826 assert_eq!(ids.len(), 1);
2827 });
2828
2829 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2831 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2832 #[rustfmt::skip]
2833 let expected = vec![
2834 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, ];
2846 assert_eq!(&frame[..], &expected[..]);
2847
2848 #[rustfmt::skip]
2850 let auth_resp_success = vec![
2851 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, ];
2863 me.on_mac_frame_rx(
2864 &auth_resp_success[..],
2865 MockWlanRxInfo::with_channel(channel.into()).into(),
2866 0.into(),
2867 )
2868 .await;
2869
2870 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2872 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2873 #[rustfmt::skip]
2874 let expected = vec![
2875 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, ];
2902 assert_eq!(&frame[..], &expected[..]);
2903
2904 #[rustfmt::skip]
2906 let assoc_resp_success = vec![
2907 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,
2921 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, ];
2934 me.on_mac_frame_rx(
2935 &assoc_resp_success[..],
2936 MockWlanRxInfo::with_channel(channel.into()).into(),
2937 0.into(),
2938 )
2939 .await;
2940
2941 let msg = m
2943 .fake_device_state
2944 .lock()
2945 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
2946 .expect("expect ConnectConf");
2947 assert_eq!(
2948 msg,
2949 fidl_mlme::ConnectConfirm {
2950 peer_sta_address: BSSID.to_array(),
2951 result_code: fidl_ieee80211::StatusCode::Success,
2952 association_id: 42,
2953 association_ies: vec![
2954 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,
2965 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
2970 }
2971 );
2972
2973 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::DOWN);
2975
2976 me.handle_mlme_req(wlan_sme::MlmeRequest::SetCtrlPort(
2978 fidl_mlme::SetControlledPortRequest {
2979 peer_sta_address: BSSID.to_array(),
2980 state: fidl_mlme::ControlledPortState::Open,
2981 },
2982 ))
2983 .await
2984 .expect("expect sending msg to succeed");
2985
2986 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
2988 }
2989
2990 #[fuchsia::test(allow_stalls = false)]
2991 async fn mlme_connect_vht() {
2992 let mut m = MockObjects::new().await;
2993 let mut me = m.make_mlme().await;
2994 let channel = Channel::new(36, Cbw::Cbw40);
2995 let connect_req = fidl_mlme::ConnectRequest {
2996 selected_bss: fake_fidl_bss_description!(Open,
2997 ssid: Ssid::try_from("ssid").unwrap().into(),
2998 bssid: BSSID.to_array(),
2999 channel: channel.clone(),
3000 ),
3001 connect_failure_timeout: 100,
3002 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
3003 sae_password: vec![],
3004 wep_key: None,
3005 security_ie: vec![],
3006 owe_public_key: None,
3007 };
3008 me.handle_mlme_req(wlan_sme::MlmeRequest::Connect(connect_req))
3009 .await
3010 .expect("Failed to send MlmeRequest::Connect.");
3011
3012 assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
3014 assert_eq!(ids.len(), 1);
3015 });
3016
3017 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
3019 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
3020
3021 #[rustfmt::skip]
3023 let auth_resp_success = vec![
3024 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, ];
3036 me.on_mac_frame_rx(
3037 &auth_resp_success[..],
3038 MockWlanRxInfo::with_channel(channel.into()).into(),
3039 0.into(),
3040 )
3041 .await;
3042
3043 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
3045 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
3046 #[rustfmt::skip]
3047 let expected = vec![
3048 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, ];
3070 assert_eq!(&frame[..], &expected[..]);
3071 }
3072
3073 #[fuchsia::test(allow_stalls = false)]
3074 async fn mlme_connect_timeout() {
3075 let mut m = MockObjects::new().await;
3076 let mut me = m.make_mlme().await;
3077 let connect_req = fidl_mlme::ConnectRequest {
3078 selected_bss: fake_fidl_bss_description!(Open, bssid: BSSID.to_array()),
3079 connect_failure_timeout: 100,
3080 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
3081 sae_password: vec![],
3082 wep_key: None,
3083 security_ie: vec![],
3084 owe_public_key: None,
3085 };
3086 me.handle_mlme_req(wlan_sme::MlmeRequest::Connect(connect_req))
3087 .await
3088 .expect("Failed to send MlmeRequest::Connect.");
3089
3090 let (event, _id) = assert_matches!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(events) => {
3092 assert_eq!(events.len(), 1);
3093 events[0].clone()
3094 });
3095
3096 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
3098 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
3099
3100 me.handle_timed_event(event).await;
3102
3103 let msg = m
3105 .fake_device_state
3106 .lock()
3107 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
3108 .expect("expect msg");
3109 assert_eq!(
3110 msg,
3111 fidl_mlme::ConnectConfirm {
3112 peer_sta_address: BSSID.to_array(),
3113 result_code: fidl_ieee80211::StatusCode::RejectedSequenceTimeout,
3114 association_id: 0,
3115 association_ies: vec![],
3116 },
3117 );
3118 }
3119
3120 #[fuchsia::test(allow_stalls = false)]
3121 async fn mlme_reconnect_no_sta() {
3122 let mut m = MockObjects::new().await;
3123 let mut me = m.make_mlme().await;
3124
3125 let reconnect_req = fidl_mlme::ReconnectRequest { peer_sta_address: [1, 2, 3, 4, 5, 6] };
3126 let result = me.handle_mlme_req(wlan_sme::MlmeRequest::Reconnect(reconnect_req)).await;
3127 assert_matches!(result, Err(Error::Status(_, zx::Status::BAD_STATE)));
3128
3129 let msg = m
3131 .fake_device_state
3132 .lock()
3133 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
3134 .expect("expect msg");
3135 assert_eq!(
3136 msg,
3137 fidl_mlme::ConnectConfirm {
3138 peer_sta_address: [1, 2, 3, 4, 5, 6],
3139 result_code: fidl_ieee80211::StatusCode::DeniedNoAssociationExists,
3140 association_id: 0,
3141 association_ies: vec![],
3142 },
3143 );
3144 }
3145
3146 #[fuchsia::test(allow_stalls = false)]
3147 async fn mlme_respond_to_get_iface_stats_with_error_status() {
3148 let mut m = MockObjects::new().await;
3149 let mut me = m.make_mlme().await;
3150
3151 let (responder, receiver) = Responder::new();
3152 me.handle_mlme_req(wlan_sme::MlmeRequest::GetIfaceStats(responder))
3153 .await
3154 .expect("Failed to send MlmeRequest::GetIfaceStats.");
3155 assert_eq!(
3156 receiver.await,
3157 Ok(fidl_mlme::GetIfaceStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED))
3158 );
3159 }
3160
3161 #[fuchsia::test(allow_stalls = false)]
3162 async fn mlme_respond_to_get_iface_histogram_stats_with_error_status() {
3163 let mut m = MockObjects::new().await;
3164 let mut me = m.make_mlme().await;
3165
3166 let (responder, receiver) = Responder::new();
3167 me.handle_mlme_req(wlan_sme::MlmeRequest::GetIfaceHistogramStats(responder))
3168 .await
3169 .expect("Failed to send MlmeRequest::GetIfaceHistogramStats");
3170 assert_eq!(
3171 receiver.await,
3172 Ok(fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(
3173 zx::sys::ZX_ERR_NOT_SUPPORTED
3174 ))
3175 );
3176 }
3177
3178 #[test]
3179 fn drop_mgmt_frame_wrong_bssid() {
3180 let frame = [
3181 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0x10, 0, ];
3189 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3190 assert_eq!(false, make_client_station().should_handle_frame(&frame));
3191 }
3192
3193 #[test]
3194 fn drop_mgmt_frame_wrong_dst_addr() {
3195 let frame = [
3196 0b11010000, 0b00000000, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3204 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3205 assert_eq!(false, make_client_station().should_handle_frame(&frame));
3206 }
3207
3208 #[test]
3209 fn mgmt_frame_ok_broadcast() {
3210 let frame = [
3211 0b11010000, 0b00000000, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3219 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3220 assert_eq!(true, make_client_station().should_handle_frame(&frame));
3221 }
3222
3223 #[test]
3224 fn mgmt_frame_ok_client_addr() {
3225 let frame = [
3226 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3234 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3235 assert_eq!(true, make_client_station().should_handle_frame(&frame));
3236 }
3237
3238 #[test]
3239 fn drop_data_frame_wrong_bssid() {
3240 let frame = [
3241 0b01001000,
3243 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3250 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3251 assert_eq!(false, make_client_station().should_handle_frame(&frame));
3252 }
3253
3254 #[test]
3255 fn drop_data_frame_wrong_dst_addr() {
3256 let frame = [
3257 0b01001000,
3259 0b00000010, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3266 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3267 assert_eq!(false, make_client_station().should_handle_frame(&frame));
3268 }
3269
3270 #[test]
3271 fn data_frame_ok_broadcast() {
3272 let frame = [
3273 0b01001000,
3275 0b00000010, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3282 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3283 assert_eq!(true, make_client_station().should_handle_frame(&frame));
3284 }
3285
3286 #[test]
3287 fn data_frame_ok_client_addr() {
3288 let frame = [
3289 0b01001000,
3291 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3298 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3299 assert_eq!(true, make_client_station().should_handle_frame(&frame));
3300 }
3301}