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