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