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::QueryDiscoverySupport(responder) => {
299 self.on_sme_query_discovery_support(responder).await
300 }
301 Req::QueryMacSublayerSupport(responder) => {
302 self.on_sme_query_mac_sublayer_support(responder).await
303 }
304 Req::QuerySecuritySupport(responder) => {
305 self.on_sme_query_security_support(responder).await
306 }
307 Req::QuerySpectrumManagementSupport(responder) => {
308 self.on_sme_query_spectrum_management_support(responder).await
309 }
310 Req::ListMinstrelPeers(responder) => self.on_sme_list_minstrel_peers(responder),
311 Req::GetMinstrelStats(req, responder) => {
312 self.on_sme_get_minstrel_stats(responder, &req.peer_addr.into())
313 }
314 other_message => match &mut self.sta {
315 None => {
316 if let Req::Reconnect(req) = other_message {
317 self.ctx.device.send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf {
318 resp: fidl_mlme::ConnectConfirm {
319 peer_sta_address: req.peer_sta_address,
320 result_code: fidl_ieee80211::StatusCode::DeniedNoAssociationExists,
321 association_id: 0,
322 association_ies: vec![],
323 },
324 })?;
325 }
326 Err(Error::Status(
327 format!(
328 "Failed to handle {} MLME request when this ClientMlme has no sta.",
329 other_message.name()
330 ),
331 zx::Status::BAD_STATE,
332 ))
333 }
334 Some(sta) => Ok(sta
335 .bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
336 .handle_mlme_req(other_message)
337 .await),
338 },
339 }
340 }
341
342 async fn on_sme_scan(&mut self, req: fidl_mlme::ScanRequest) {
343 let txn_id = req.txn_id;
344 let _ = self.scanner.bind(&mut self.ctx).on_sme_scan(req).await.map_err(|e| {
345 error!("Scan failed in MLME: {:?}", e);
346 let code = match e {
347 Error::ScanError(scan_error) => scan_error.into(),
348 _ => fidl_mlme::ScanResultCode::InternalError,
349 };
350 self.ctx
351 .device
352 .send_mlme_event(fidl_mlme::MlmeEvent::OnScanEnd {
353 end: fidl_mlme::ScanEnd { txn_id, code },
354 })
355 .unwrap_or_else(|e| error!("error sending MLME ScanEnd: {}", e));
356 });
357 }
358
359 pub async fn handle_scan_complete(&mut self, status: zx::Status, scan_id: u64) {
360 self.scanner.bind(&mut self.ctx).handle_scan_complete(status, scan_id).await;
361 }
362
363 async fn on_sme_connect(&mut self, req: fidl_mlme::ConnectRequest) -> Result<(), Error> {
364 if let Err(e) = self.scanner.bind(&mut self.ctx).cancel_ongoing_scan().await {
367 warn!("Failed to cancel ongoing scan before connect: {}.", e);
368 }
369
370 let bssid = req.selected_bss.bssid;
371 let result = match req.selected_bss.try_into() {
372 Ok(bss) => {
373 let req = ParsedConnectRequest {
374 selected_bss: bss,
375 connect_failure_timeout: req.connect_failure_timeout,
376 auth_type: req.auth_type,
377 sae_password: req.sae_password,
378 wep_key: req.wep_key.map(|k| *k),
379 security_ie: req.security_ie,
380 };
381 self.join_device(&req.selected_bss).await.map(|cap| (req, cap))
382 }
383 Err(e) => Err(Error::Status(
384 format!("Error parsing BssDescription: {:?}", e),
385 zx::Status::IO_INVALID,
386 )),
387 };
388
389 match result {
390 Ok((req, client_capabilities)) => {
391 self.sta.replace(Client::new(
392 req,
393 device::try_query_iface_mac(&mut self.ctx.device).await?,
394 client_capabilities,
395 ));
396 if let Some(sta) = &mut self.sta {
397 sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
398 .start_connecting()
399 .await;
400 }
401 Ok(())
402 }
403 Err(e) => {
404 error!("Error setting up device for join: {}", e);
405 self.ctx.device.send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf {
408 resp: fidl_mlme::ConnectConfirm {
409 peer_sta_address: bssid,
410 result_code: fidl_ieee80211::StatusCode::JoinFailure,
411 association_id: 0,
412 association_ies: vec![],
413 },
414 })?;
415 Err(e)
416 }
417 }
418 }
419
420 async fn join_device(&mut self, bss: &BssDescription) -> Result<ClientCapabilities, Error> {
421 let info = ddk_converter::mlme_device_info_from_softmac(
422 device::try_query(&mut self.ctx.device).await?,
423 )?;
424 let join_caps = derive_join_capabilities(Channel::from(bss.channel), bss.rates(), &info)
425 .map_err(|e| {
426 Error::Status(
427 format!("Failed to derive join capabilities: {:?}", e),
428 zx::Status::NOT_SUPPORTED,
429 )
430 })?;
431
432 self.set_main_channel(bss.channel.into())
433 .await
434 .map_err(|status| Error::Status(format!("Error setting device channel"), status))?;
435
436 let join_bss_request = fidl_common::JoinBssRequest {
437 bssid: Some(bss.bssid.to_array()),
438 bss_type: Some(fidl_common::BssType::Infrastructure),
439 remote: Some(true),
440 beacon_period: Some(bss.beacon_period),
441 ..Default::default()
442 };
443
444 self.ctx
446 .device
447 .join_bss(&join_bss_request)
448 .await
449 .map(|()| join_caps)
450 .map_err(|status| Error::Status(format!("Error setting BSS in driver"), status))
451 }
452
453 async fn on_sme_query_device_info(
454 &mut self,
455 responder: wlan_sme::responder::Responder<fidl_mlme::DeviceInfo>,
456 ) -> Result<(), Error> {
457 let info = ddk_converter::mlme_device_info_from_softmac(
458 device::try_query(&mut self.ctx.device).await?,
459 )?;
460 responder.respond(info);
461 Ok(())
462 }
463
464 async fn on_sme_query_discovery_support(
465 &mut self,
466 responder: wlan_sme::responder::Responder<fidl_common::DiscoverySupport>,
467 ) -> Result<(), Error> {
468 let support = device::try_query_discovery_support(&mut self.ctx.device).await?;
469 responder.respond(support);
470 Ok(())
471 }
472
473 async fn on_sme_query_mac_sublayer_support(
474 &mut self,
475 responder: wlan_sme::responder::Responder<fidl_common::MacSublayerSupport>,
476 ) -> Result<(), Error> {
477 let support = device::try_query_mac_sublayer_support(&mut self.ctx.device).await?;
478 responder.respond(support);
479 Ok(())
480 }
481
482 async fn on_sme_query_security_support(
483 &mut self,
484 responder: wlan_sme::responder::Responder<fidl_common::SecuritySupport>,
485 ) -> Result<(), Error> {
486 let support = device::try_query_security_support(&mut self.ctx.device).await?;
487 responder.respond(support);
488 Ok(())
489 }
490
491 async fn on_sme_query_spectrum_management_support(
492 &mut self,
493 responder: wlan_sme::responder::Responder<fidl_common::SpectrumManagementSupport>,
494 ) -> Result<(), Error> {
495 let support = device::try_query_spectrum_management_support(&mut self.ctx.device).await?;
496 responder.respond(support);
497 Ok(())
498 }
499
500 pub fn on_eth_frame_tx<B: SplitByteSlice>(
501 &mut self,
502 bytes: B,
503 async_id: trace::Id,
504 ) -> Result<(), Error> {
505 wtrace::duration!(c"ClientMlme::on_eth_frame_tx");
506 match self.sta.as_mut() {
507 None => Err(Error::Status(
508 format!("Ethernet frame dropped (Client does not exist)."),
509 zx::Status::BAD_STATE,
510 )),
511 Some(sta) => sta
512 .bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
513 .on_eth_frame_tx(bytes, async_id),
514 }
515 }
516
517 pub async fn handle_timed_event(&mut self, event: TimedEvent) {
520 if let Some(sta) = self.sta.as_mut() {
521 return sta
522 .bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state)
523 .handle_timed_event(event)
524 .await;
525 }
526 }
527}
528
529pub struct Client {
533 state: Option<States>,
534 pub connect_req: ParsedConnectRequest,
535 pub iface_mac: MacAddr,
536 pub client_capabilities: ClientCapabilities,
537 pub connect_timeout: Option<EventHandle>,
538}
539
540impl Client {
541 pub fn new(
542 connect_req: ParsedConnectRequest,
543 iface_mac: MacAddr,
544 client_capabilities: ClientCapabilities,
545 ) -> Self {
546 Self {
547 state: Some(States::new_initial()),
548 connect_req,
549 iface_mac,
550 client_capabilities,
551 connect_timeout: None,
552 }
553 }
554
555 pub fn ssid(&self) -> &Ssid {
556 &self.connect_req.selected_bss.ssid
557 }
558
559 pub fn bssid(&self) -> Bssid {
560 self.connect_req.selected_bss.bssid
561 }
562
563 pub fn beacon_period(&self) -> zx::MonotonicDuration {
564 zx::MonotonicDuration::from(TimeUnit(self.connect_req.selected_bss.beacon_period))
565 }
566
567 pub fn eapol_required(&self) -> bool {
568 self.connect_req.selected_bss.rsne().is_some()
569 || self.connect_req.selected_bss.find_wpa_ie().is_some()
573 }
574
575 pub fn bind<'a, D>(
576 &'a mut self,
577 ctx: &'a mut Context<D>,
578 scanner: &'a mut Scanner,
579 channel_state: &'a mut ChannelState,
580 ) -> BoundClient<'a, D> {
581 BoundClient { sta: self, ctx, scanner, channel_state }
582 }
583
584 fn should_handle_frame<B: SplitByteSlice>(&self, mac_frame: &mac::MacFrame<B>) -> bool {
588 wtrace::duration!(c"Client::should_handle_frame");
589
590 let (src_addr, dst_addr) = match mac_frame {
593 mac::MacFrame::Mgmt(mac::MgmtFrame { mgmt_hdr, .. }) => {
594 (Some(mgmt_hdr.addr3), mgmt_hdr.addr1)
595 }
596 mac::MacFrame::Data(mac::DataFrame { fixed_fields, .. }) => {
597 (mac::data_bssid(&fixed_fields), mac::data_dst_addr(&fixed_fields))
598 }
599 _ => return false,
601 };
602 src_addr.is_some_and(|src_addr| src_addr == self.bssid().into())
603 && (!dst_addr.is_unicast() || dst_addr == self.iface_mac)
604 }
605}
606
607pub struct BoundClient<'a, D> {
608 sta: &'a mut Client,
609 ctx: &'a mut Context<D>,
611 scanner: &'a mut Scanner,
612 channel_state: &'a mut ChannelState,
613}
614
615impl<'a, D: DeviceOps> akm_algorithm::AkmAction for BoundClient<'a, D> {
616 fn send_auth_frame(
617 &mut self,
618 auth_type: mac::AuthAlgorithmNumber,
619 seq_num: u16,
620 result_code: mac::StatusCode,
621 auth_content: &[u8],
622 ) -> Result<(), anyhow::Error> {
623 self.send_auth_frame(auth_type, seq_num, result_code, auth_content).map_err(|e| e.into())
624 }
625
626 fn forward_sme_sae_rx(
627 &mut self,
628 seq_num: u16,
629 status_code: fidl_ieee80211::StatusCode,
630 sae_fields: Vec<u8>,
631 ) {
632 self.forward_sae_frame_rx(seq_num, status_code, sae_fields)
633 }
634
635 fn forward_sae_handshake_ind(&mut self) {
636 self.forward_sae_handshake_ind()
637 }
638}
639
640impl<'a, D: DeviceOps> BoundClient<'a, D> {
641 fn deliver_msdu<B: SplitByteSlice>(&mut self, msdu: mac::Msdu<B>) -> Result<(), Error> {
645 let mac::Msdu { dst_addr, src_addr, llc_frame } = msdu;
646
647 let mut packet = [0u8; mac::MAX_ETH_FRAME_LEN];
648 let (frame_start, frame_end) = write_frame_with_fixed_slice!(&mut packet[..], {
649 headers: {
650 mac::EthernetIIHdr: &mac::EthernetIIHdr {
651 da: dst_addr,
652 sa: src_addr,
653 ether_type: llc_frame.hdr.protocol_id,
654 },
655 },
656 payload: &llc_frame.body,
657 })?;
658 self.ctx
659 .device
660 .deliver_eth_frame(&packet[frame_start..frame_end])
661 .map_err(|s| Error::Status(format!("could not deliver Ethernet II frame"), s))
662 }
663
664 pub fn send_auth_frame(
665 &mut self,
666 auth_type: mac::AuthAlgorithmNumber,
667 seq_num: u16,
668 result_code: mac::StatusCode,
669 auth_content: &[u8],
670 ) -> Result<(), Error> {
671 let buffer = write_frame!({
672 headers: {
673 mac::MgmtHdr: &mgmt_writer::mgmt_hdr_to_ap(
674 mac::FrameControl(0)
675 .with_frame_type(mac::FrameType::MGMT)
676 .with_mgmt_subtype(mac::MgmtSubtype::AUTH),
677 self.sta.bssid(),
678 self.sta.iface_mac,
679 mac::SequenceControl(0)
680 .with_seq_num(self.ctx.seq_mgr.next_sns1(&self.sta.bssid().into()) as u16)
681 ),
682 mac::AuthHdr: &mac::AuthHdr {
683 auth_alg_num: auth_type,
684 auth_txn_seq_num: seq_num,
685 status_code: result_code,
686 },
687 },
688 body: auth_content,
689 })?;
690 self.send_mgmt_or_ctrl_frame(buffer)
691 .map_err(|s| Error::Status(format!("error sending open auth frame"), s))
692 }
693
694 pub fn send_open_auth_frame(&mut self) -> Result<(), Error> {
696 self.send_auth_frame(
697 mac::AuthAlgorithmNumber::OPEN,
698 1,
699 fidl_ieee80211::StatusCode::Success.into(),
700 &[],
701 )
702 }
703
704 pub fn send_assoc_req_frame(&mut self) -> Result<(), Error> {
706 let ssid = self.sta.ssid().clone();
707 let cap = &self.sta.client_capabilities.0;
708 let capability_info = cap.capability_info.0;
709 let rates: Vec<u8> = cap.rates.iter().map(|r| r.rate()).collect();
710 let ht_cap = cap.ht_cap;
711 let vht_cap = cap.vht_cap;
712 let security_ie = self.sta.connect_req.security_ie.clone();
713
714 let rsne = (!security_ie.is_empty() && security_ie[0] == ie::Id::RSNE.0)
715 .then(|| match rsne::from_bytes(&security_ie[..]) {
716 Ok((_, x)) => Ok(x),
717 Err(e) => Err(format_err!("error parsing rsne {:?} : {:?}", security_ie, e)),
718 })
719 .transpose()?;
720 let buffer = write_frame!({
721 headers: {
722 mac::MgmtHdr: &mgmt_writer::mgmt_hdr_to_ap(
723 mac::FrameControl(0)
724 .with_frame_type(mac::FrameType::MGMT)
725 .with_mgmt_subtype(mac::MgmtSubtype::ASSOC_REQ),
726 self.sta.bssid(),
727 self.sta.iface_mac,
728 mac::SequenceControl(0)
729 .with_seq_num(self.ctx.seq_mgr.next_sns1(&self.sta.bssid().into()) as u16)
730 ),
731 mac::AssocReqHdr: &mac::AssocReqHdr {
732 capabilities: mac::CapabilityInfo(capability_info),
733 listen_interval: 0,
734 },
735 },
736 ies: {
737 ssid: ssid,
738 supported_rates: rates,
739 extended_supported_rates: {},
740 rsne?: rsne,
741 ht_cap?: ht_cap,
742 vht_cap?: vht_cap,
743 },
744 })?;
745 self.send_mgmt_or_ctrl_frame(buffer)
746 .map_err(|s| Error::Status(format!("error sending assoc req frame"), s))
747 }
748
749 fn send_keep_alive_resp_frame(&mut self) -> Result<(), Error> {
755 let buffer = write_frame!({
756 headers: {
757 mac::FixedDataHdrFields: &data_writer::data_hdr_client_to_ap(
758 mac::FrameControl(0)
759 .with_frame_type(mac::FrameType::DATA)
760 .with_data_subtype(mac::DataSubtype(0).with_null(true)),
761 self.sta.bssid(),
762 self.sta.iface_mac,
763 mac::SequenceControl(0)
764 .with_seq_num(self.ctx.seq_mgr.next_sns1(&self.sta.bssid().into()) as u16)
765 ),
766 },
767 })?;
768 self.ctx
769 .device
770 .send_wlan_frame(buffer, fidl_softmac::WlanTxInfoFlags::empty(), None)
771 .map_err(|s| Error::Status(format!("error sending keep alive frame"), s))
772 }
773
774 pub fn send_deauth_frame(&mut self, reason_code: mac::ReasonCode) -> Result<(), Error> {
775 let buffer = write_frame!({
776 headers: {
777 mac::MgmtHdr: &mgmt_writer::mgmt_hdr_to_ap(
778 mac::FrameControl(0)
779 .with_frame_type(mac::FrameType::MGMT)
780 .with_mgmt_subtype(mac::MgmtSubtype::DEAUTH),
781 self.sta.bssid(),
782 self.sta.iface_mac,
783 mac::SequenceControl(0)
784 .with_seq_num(self.ctx.seq_mgr.next_sns1(&self.sta.bssid().into()) as u16)
785 ),
786 mac::DeauthHdr: &mac::DeauthHdr {
787 reason_code,
788 },
789 },
790 })?;
791 let result = self
792 .send_mgmt_or_ctrl_frame(buffer)
793 .map_err(|s| Error::Status(format!("error sending deauthenticate frame"), s));
794 self.channel_state.bind(&mut self.ctx, &mut self.scanner).clear_main_channel();
796
797 result
798 }
799
800 pub fn send_data_frame(
804 &mut self,
805 src: MacAddr,
806 dst: MacAddr,
807 is_protected: bool,
808 qos_ctrl: bool,
809 ether_type: u16,
810 payload: &[u8],
811 async_id: Option<trace::Id>,
812 ) -> Result<(), Error> {
813 let async_id_provided = async_id.is_some();
814 let async_id = async_id.unwrap_or_else(|| {
815 let async_id = trace::Id::new();
816 wtrace::async_begin_wlansoftmac_tx(async_id, "mlme");
817 async_id
818 });
819 wtrace::duration!(c"BoundClient::send_data_frame");
820
821 let qos_ctrl = if qos_ctrl {
822 Some(
823 wmm::derive_tid(ether_type, payload)
824 .map_or(mac::QosControl(0), |tid| mac::QosControl(0).with_tid(tid as u16)),
825 )
826 } else {
827 None
828 };
829
830 let to_ds = true;
837 let from_ds = src != self.sta.iface_mac;
838 let addr1 = self.sta.bssid().into();
840 let addr2 = self.sta.iface_mac;
841 let addr3 = match (to_ds, from_ds) {
842 (false, false) => self.sta.bssid().into(),
843 (false, true) => src,
844 (true, _) => dst,
845 };
846 let addr4 = if from_ds && to_ds { Some(src) } else { None };
847
848 let tx_flags = match ether_type {
849 mac::ETHER_TYPE_EAPOL => fidl_softmac::WlanTxInfoFlags::FAVOR_RELIABILITY,
850 _ => fidl_softmac::WlanTxInfoFlags::empty(),
851 };
852
853 const MAX_HEADER_SIZE: usize = mem::size_of::<mac::FixedDataHdrFields>()
857 + mem::size_of::<MacAddr>()
858 + mem::size_of::<mac::QosControl>()
859 + mem::size_of::<mac::LlcHdr>();
860 let header_room = MAX_HEADER_SIZE + 100;
861 let arena = Arena::new();
862 let mut buffer = arena.insert_default_slice(header_room + payload.len());
863
864 let payload_start = buffer.len() - payload.len();
867 buffer[payload_start..].clone_from_slice(&payload[..]);
868
869 let (frame_start, _frame_end) =
870 write_frame_with_fixed_slice!(&mut buffer[..payload_start], {
871 fill_zeroes: (),
872 headers: {
873 mac::FixedDataHdrFields: &mac::FixedDataHdrFields {
874 frame_ctrl: mac::FrameControl(0)
875 .with_frame_type(mac::FrameType::DATA)
876 .with_data_subtype(mac::DataSubtype(0).with_qos(qos_ctrl.is_some()))
877 .with_protected(is_protected)
878 .with_to_ds(to_ds)
879 .with_from_ds(from_ds),
880 duration: 0,
881 addr1,
882 addr2,
883 addr3,
884 seq_ctrl: mac::SequenceControl(0).with_seq_num(
885 match qos_ctrl.as_ref() {
886 None => self.ctx.seq_mgr.next_sns1(&dst),
887 Some(qos_ctrl) => self.ctx.seq_mgr.next_sns2(&dst, qos_ctrl.tid()),
888 } as u16
889 )
890 },
891 mac::Addr4?: addr4,
892 mac::QosControl?: qos_ctrl,
893 mac::LlcHdr: &data_writer::make_snap_llc_hdr(ether_type),
894 },
895 })
896 .map_err(|e| {
897 if !async_id_provided {
898 wtrace::async_end_wlansoftmac_tx(async_id, zx::Status::INTERNAL);
899 }
900 e
901 })?;
902
903 let buffer = unsafe {
907 arena.assume_unchecked(NonNull::new_unchecked(
908 &mut ArenaBox::into_ptr(buffer).as_mut()[frame_start..],
909 ))
910 };
911 let buffer = arena.make_static(buffer);
912 self.ctx.device.send_wlan_frame(buffer, tx_flags, Some(async_id)).map_err(|s| {
913 if !async_id_provided {
914 wtrace::async_end_wlansoftmac_tx(async_id, s);
915 }
916 Error::Status(format!("error sending data frame"), s)
917 })
918 }
919
920 fn send_eapol_indication(
923 &mut self,
924 src_addr: MacAddr,
925 dst_addr: MacAddr,
926 eapol_frame: &[u8],
927 ) -> Result<(), Error> {
928 self.ctx
929 .device
930 .send_mlme_event(fidl_mlme::MlmeEvent::EapolInd {
931 ind: fidl_mlme::EapolIndication {
932 src_addr: src_addr.to_array(),
933 dst_addr: dst_addr.to_array(),
934 data: eapol_frame.to_vec(),
935 },
936 })
937 .map_err(|e| e.into())
938 }
939
940 pub fn send_eapol_frame(
943 &mut self,
944 src: MacAddr,
945 dst: MacAddr,
946 is_protected: bool,
947 eapol_frame: &[u8],
948 ) {
949 let result = self.send_data_frame(
952 src,
953 dst,
954 is_protected,
955 false, mac::ETHER_TYPE_EAPOL,
957 eapol_frame,
958 None,
959 );
960 let result_code = match result {
961 Ok(()) => fidl_mlme::EapolResultCode::Success,
962 Err(e) => {
963 error!("error sending EAPoL frame: {}", e);
964 fidl_mlme::EapolResultCode::TransmissionFailure
965 }
966 };
967
968 self.ctx
970 .device
971 .send_mlme_event(fidl_mlme::MlmeEvent::EapolConf {
972 resp: fidl_mlme::EapolConfirm { result_code, dst_addr: dst.to_array() },
973 })
974 .unwrap_or_else(|e| error!("error sending MLME-EAPOL.confirm message: {}", e));
975 }
976
977 pub fn send_ps_poll_frame(&mut self, aid: Aid) -> Result<(), Error> {
978 const PS_POLL_ID_MASK: u16 = 0b11000000_00000000;
979
980 let buffer = write_frame!({
981 headers: {
982 mac::FrameControl: &mac::FrameControl(0)
983 .with_frame_type(mac::FrameType::CTRL)
984 .with_ctrl_subtype(mac::CtrlSubtype::PS_POLL),
985 mac::PsPoll: &mac::PsPoll {
986 masked_aid: aid | PS_POLL_ID_MASK,
989 bssid: self.sta.bssid(),
990 ta: self.sta.iface_mac,
991 },
992 },
993 })?;
994 self.send_mgmt_or_ctrl_frame(buffer)
995 .map_err(|s| Error::Status(format!("error sending PS-Poll frame"), s))
996 }
997
998 pub async fn handle_timed_event(&mut self, event: TimedEvent) {
1000 self.sta.state = Some(self.sta.state.take().unwrap().on_timed_event(self, event).await)
1001 }
1002
1003 pub async fn on_mac_frame<B: SplitByteSlice>(
1005 &mut self,
1006 bytes: B,
1007 rx_info: fidl_softmac::WlanRxInfo,
1008 async_id: trace::Id,
1009 ) {
1010 wtrace::duration!(c"BoundClient::on_mac_frame");
1011 self.sta.state =
1013 Some(self.sta.state.take().unwrap().on_mac_frame(self, bytes, rx_info, async_id).await);
1014 }
1015
1016 pub fn on_eth_frame_tx<B: SplitByteSlice>(
1017 &mut self,
1018 frame: B,
1019 async_id: trace::Id,
1020 ) -> Result<(), Error> {
1021 wtrace::duration!(c"BoundClient::on_eth_frame_tx");
1022 let state = self.sta.state.take().unwrap();
1024 let result = state.on_eth_frame(self, frame, async_id);
1025 self.sta.state.replace(state);
1026 result
1027 }
1028
1029 pub async fn start_connecting(&mut self) {
1030 let next_state = self.sta.state.take().unwrap().start_connecting(self).await;
1032 self.sta.state.replace(next_state);
1033 }
1034
1035 pub async fn handle_mlme_req(&mut self, msg: wlan_sme::MlmeRequest) {
1036 let next_state = self.sta.state.take().unwrap().handle_mlme_req(self, msg).await;
1038 self.sta.state.replace(next_state);
1039 }
1040
1041 fn send_connect_conf_failure(&mut self, result_code: fidl_ieee80211::StatusCode) {
1042 self.sta.connect_timeout.take();
1043 let bssid = self.sta.connect_req.selected_bss.bssid;
1044 self.send_connect_conf_failure_with_bssid(bssid, result_code);
1045 }
1046
1047 fn send_connect_conf_failure_with_bssid(
1050 &mut self,
1051 bssid: Bssid,
1052 result_code: fidl_ieee80211::StatusCode,
1053 ) {
1054 let connect_conf = fidl_mlme::ConnectConfirm {
1055 peer_sta_address: bssid.to_array(),
1056 result_code,
1057 association_id: 0,
1058 association_ies: vec![],
1059 };
1060 self.ctx
1061 .device
1062 .send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf { resp: connect_conf })
1063 .unwrap_or_else(|e| error!("error sending MLME-CONNECT.confirm: {}", e));
1064 }
1065
1066 fn send_connect_conf_success<B: SplitByteSlice>(
1067 &mut self,
1068 association_id: mac::Aid,
1069 association_ies: B,
1070 ) {
1071 self.sta.connect_timeout.take();
1072 let connect_conf = fidl_mlme::ConnectConfirm {
1073 peer_sta_address: self.sta.connect_req.selected_bss.bssid.to_array(),
1074 result_code: fidl_ieee80211::StatusCode::Success,
1075 association_id,
1076 association_ies: association_ies.to_vec(),
1077 };
1078 self.ctx
1079 .device
1080 .send_mlme_event(fidl_mlme::MlmeEvent::ConnectConf { resp: connect_conf })
1081 .unwrap_or_else(|e| error!("error sending MLME-CONNECT.confirm: {}", e));
1082 }
1083
1084 fn send_deauthenticate_ind(
1086 &mut self,
1087 reason_code: fidl_ieee80211::ReasonCode,
1088 locally_initiated: LocallyInitiated,
1089 ) {
1090 self.channel_state.bind(&mut self.ctx, &mut self.scanner).clear_main_channel();
1092
1093 self.ctx
1094 .device
1095 .send_mlme_event(fidl_mlme::MlmeEvent::DeauthenticateInd {
1096 ind: fidl_mlme::DeauthenticateIndication {
1097 peer_sta_address: self.sta.bssid().to_array(),
1098 reason_code,
1099 locally_initiated: locally_initiated.0,
1100 },
1101 })
1102 .unwrap_or_else(|e| error!("error sending MLME-DEAUTHENTICATE.indication: {}", e));
1103 }
1104
1105 fn send_disassoc_ind(
1107 &mut self,
1108 reason_code: fidl_ieee80211::ReasonCode,
1109 locally_initiated: LocallyInitiated,
1110 ) {
1111 self.ctx
1112 .device
1113 .send_mlme_event(fidl_mlme::MlmeEvent::DisassociateInd {
1114 ind: fidl_mlme::DisassociateIndication {
1115 peer_sta_address: self.sta.bssid().to_array(),
1116 reason_code,
1117 locally_initiated: locally_initiated.0,
1118 },
1119 })
1120 .unwrap_or_else(|e| error!("error sending MLME-DISASSOCIATE.indication: {}", e));
1121 }
1122
1123 async fn clear_association(&mut self) -> Result<(), zx::Status> {
1124 self.ctx
1125 .device
1126 .clear_association(&fidl_softmac::WlanSoftmacBaseClearAssociationRequest {
1127 peer_addr: Some(self.sta.bssid().to_array()),
1128 ..Default::default()
1129 })
1130 .await
1131 }
1132
1133 fn forward_sae_frame_rx(
1135 &mut self,
1136 seq_num: u16,
1137 status_code: fidl_ieee80211::StatusCode,
1138 sae_fields: Vec<u8>,
1139 ) {
1140 self.ctx
1141 .device
1142 .send_mlme_event(fidl_mlme::MlmeEvent::OnSaeFrameRx {
1143 frame: fidl_mlme::SaeFrame {
1144 peer_sta_address: self.sta.bssid().to_array(),
1145 seq_num,
1146 status_code,
1147 sae_fields,
1148 },
1149 })
1150 .unwrap_or_else(|e| error!("error sending OnSaeFrameRx: {}", e));
1151 }
1152
1153 fn forward_sae_handshake_ind(&mut self) {
1154 self.ctx
1155 .device
1156 .send_mlme_event(fidl_mlme::MlmeEvent::OnSaeHandshakeInd {
1157 ind: fidl_mlme::SaeHandshakeIndication {
1158 peer_sta_address: self.sta.bssid().to_array(),
1159 },
1160 })
1161 .unwrap_or_else(|e| error!("error sending OnSaeHandshakeInd: {}", e));
1162 }
1163
1164 fn send_mgmt_or_ctrl_frame(&mut self, buffer: ArenaStaticBox<[u8]>) -> Result<(), zx::Status> {
1165 self.ctx.device.send_wlan_frame(buffer, fidl_softmac::WlanTxInfoFlags::empty(), None)
1166 }
1167}
1168
1169pub struct ParsedConnectRequest {
1170 pub selected_bss: BssDescription,
1171 pub connect_failure_timeout: u32,
1172 pub auth_type: fidl_mlme::AuthenticationTypes,
1173 pub sae_password: Vec<u8>,
1174 pub wep_key: Option<fidl_mlme::SetKeyDescriptor>,
1175 pub security_ie: Vec<u8>,
1176}
1177
1178pub struct ParsedAssociateResp {
1179 pub association_id: u16,
1180 pub capabilities: CapabilityInfo,
1181 pub rates: Vec<ie::SupportedRate>,
1182 pub ht_cap: Option<ie::HtCapabilities>,
1183 pub vht_cap: Option<ie::VhtCapabilities>,
1184}
1185
1186impl ParsedAssociateResp {
1187 pub fn parse<B: SplitByteSlice>(assoc_resp_frame: &mac::AssocRespFrame<B>) -> Self {
1188 let mut parsed = ParsedAssociateResp {
1189 association_id: assoc_resp_frame.assoc_resp_hdr.aid,
1190 capabilities: assoc_resp_frame.assoc_resp_hdr.capabilities,
1191 rates: vec![],
1192 ht_cap: None,
1193 vht_cap: None,
1194 };
1195 for (id, body) in assoc_resp_frame.ies() {
1196 match id {
1197 Id::SUPPORTED_RATES => match ie::parse_supported_rates(body) {
1198 Err(e) => warn!("invalid Supported Rates: {}", e),
1199 Ok(supported_rates) => {
1200 parsed.rates.extend(supported_rates.iter());
1202 }
1203 },
1204 Id::EXTENDED_SUPPORTED_RATES => match ie::parse_extended_supported_rates(body) {
1205 Err(e) => warn!("invalid Extended Supported Rates: {}", e),
1206 Ok(supported_rates) => {
1207 parsed.rates.extend(supported_rates.iter());
1209 }
1210 },
1211 Id::HT_CAPABILITIES => match ie::parse_ht_capabilities(body) {
1212 Err(e) => warn!("invalid HT Capabilities: {}", e),
1213 Ok(ht_cap) => {
1214 parsed.ht_cap = Some(*ht_cap);
1215 }
1216 },
1217 Id::VHT_CAPABILITIES => match ie::parse_vht_capabilities(body) {
1218 Err(e) => warn!("invalid VHT Capabilities: {}", e),
1219 Ok(vht_cap) => {
1220 parsed.vht_cap = Some(*vht_cap);
1221 }
1222 },
1223 _ => {}
1225 }
1226 }
1227 parsed
1228 }
1229}
1230
1231impl<'a, D: DeviceOps> BlockAckTx for BoundClient<'a, D> {
1232 fn send_block_ack_frame(&mut self, n: usize, body: &[u8]) -> Result<(), Error> {
1236 let arena = Arena::new();
1237 let buffer = arena.insert_default_slice::<u8>(n);
1238 let mut buffer = arena.make_static(buffer);
1239 let mut writer = BufferWriter::new(&mut buffer[..]);
1240 write_block_ack_hdr(
1241 &mut writer,
1242 self.sta.bssid(),
1243 self.sta.iface_mac,
1244 &mut self.ctx.seq_mgr,
1245 )
1246 .and_then(|_| writer.append_bytes(body).map_err(Into::into))?;
1247 self.send_mgmt_or_ctrl_frame(buffer)
1248 .map_err(|status| Error::Status(format!("error sending BlockAck frame"), status))
1249 }
1250}
1251
1252fn write_block_ack_hdr<B: Append>(
1257 buffer: &mut B,
1258 bssid: Bssid,
1259 addr: MacAddr,
1260 seq_mgr: &mut SequenceManager,
1261) -> Result<(), Error> {
1262 Ok(append_frame_to!(
1266 buffer,
1267 {
1268 headers: {
1269 mac::MgmtHdr: &mgmt_writer::mgmt_hdr_to_ap(
1270 mac::FrameControl(0)
1271 .with_frame_type(mac::FrameType::MGMT)
1272 .with_mgmt_subtype(mac::MgmtSubtype::ACTION),
1273 bssid,
1274 addr,
1275 mac::SequenceControl(0)
1276 .with_seq_num(seq_mgr.next_sns1(&bssid.into()) as u16),
1277 ),
1278 },
1279 }
1280 )
1281 .map(|_buffer| {})?)
1282}
1283
1284#[cfg(test)]
1285mod tests {
1286 use super::state::DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT;
1287 use super::*;
1288 use crate::block_ack::{
1289 self, BlockAckState, Closed, ADDBA_REQ_FRAME_LEN, ADDBA_RESP_FRAME_LEN,
1290 };
1291 use crate::client::lost_bss::LostBssCounter;
1292 use crate::client::test_utils::drain_timeouts;
1293 use crate::device::{test_utils, FakeDevice, FakeDeviceConfig, FakeDeviceState, LinkStatus};
1294 use crate::test_utils::{fake_wlan_channel, MockWlanRxInfo};
1295 use fuchsia_sync::Mutex;
1296 use lazy_static::lazy_static;
1297 use std::sync::Arc;
1298 use wlan_common::capabilities::StaCapabilities;
1299 use wlan_common::channel::Cbw;
1300 use wlan_common::stats::SignalStrengthAverage;
1301 use wlan_common::test_utils::fake_capabilities::fake_client_capabilities;
1302 use wlan_common::test_utils::fake_frames::*;
1303 use wlan_common::timer::{self, create_timer};
1304 use wlan_common::{assert_variant, fake_bss_description, fake_fidl_bss_description};
1305 use wlan_sme::responder::Responder;
1306 use wlan_statemachine::*;
1307 use {fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_internal as fidl_internal};
1308 lazy_static! {
1309 static ref BSSID: Bssid = [6u8; 6].into();
1310 static ref IFACE_MAC: MacAddr = [7u8; 6].into();
1311 }
1312 const RSNE: &[u8] = &[
1313 0x30, 0x14, 1, 0, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x02, 0xa8, 0x04, ];
1322 const SCAN_CHANNEL_PRIMARY: u8 = 6;
1323 #[rustfmt::skip]
1325 const BEACON_FRAME: &'static [u8] = &[
1326 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, ];
1343
1344 struct MockObjects {
1345 fake_device: FakeDevice,
1346 fake_device_state: Arc<Mutex<FakeDeviceState>>,
1347 timer: Option<Timer<super::TimedEvent>>,
1348 time_stream: timer::EventStream<super::TimedEvent>,
1349 }
1350
1351 impl MockObjects {
1352 async fn new() -> Self {
1356 let (timer, time_stream) = create_timer();
1357 let (fake_device, fake_device_state) = FakeDevice::new_with_config(
1358 FakeDeviceConfig::default()
1359 .with_mock_mac_role(fidl_common::WlanMacRole::Client)
1360 .with_mock_sta_addr((*IFACE_MAC).to_array()),
1361 )
1362 .await;
1363 Self { fake_device, fake_device_state, timer: Some(timer), time_stream }
1364 }
1365
1366 async fn make_mlme(&mut self) -> ClientMlme<FakeDevice> {
1367 let mut mlme = ClientMlme::new(
1368 Default::default(),
1369 self.fake_device.clone(),
1370 self.timer.take().unwrap(),
1371 )
1372 .await
1373 .expect("Failed to create client MLME.");
1374 mlme.set_main_channel(fake_wlan_channel().into())
1375 .await
1376 .expect("unable to set main channel");
1377 mlme
1378 }
1379 }
1380
1381 fn scan_req() -> fidl_mlme::ScanRequest {
1382 fidl_mlme::ScanRequest {
1383 txn_id: 1337,
1384 scan_type: fidl_mlme::ScanTypes::Passive,
1385 channel_list: vec![SCAN_CHANNEL_PRIMARY],
1386 ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
1387 probe_delay: 0,
1388 min_channel_time: 100,
1389 max_channel_time: 300,
1390 }
1391 }
1392
1393 fn make_client_station() -> Client {
1394 let connect_req = ParsedConnectRequest {
1395 selected_bss: fake_bss_description!(Open, 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: vec![],
1401 };
1402 Client::new(connect_req, *IFACE_MAC, fake_client_capabilities())
1403 }
1404
1405 fn make_client_station_protected() -> Client {
1406 let connect_req = ParsedConnectRequest {
1407 selected_bss: fake_bss_description!(Wpa2, bssid: BSSID.to_array()),
1408 connect_failure_timeout: 100,
1409 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1410 sae_password: vec![],
1411 wep_key: None,
1412 security_ie: RSNE.to_vec(),
1413 };
1414 Client::new(connect_req, *IFACE_MAC, fake_client_capabilities())
1415 }
1416
1417 impl ClientMlme<FakeDevice> {
1418 fn make_client_station(&mut self) {
1419 self.sta.replace(make_client_station());
1420 }
1421
1422 fn make_client_station_protected(&mut self) {
1423 self.sta.replace(make_client_station_protected());
1424 }
1425
1426 fn get_bound_client(&mut self) -> Option<BoundClient<'_, FakeDevice>> {
1427 match self.sta.as_mut() {
1428 None => None,
1429 Some(sta) => {
1430 Some(sta.bind(&mut self.ctx, &mut self.scanner, &mut self.channel_state))
1431 }
1432 }
1433 }
1434 }
1435
1436 impl BoundClient<'_, FakeDevice> {
1437 fn move_to_associated_state(&mut self) {
1438 use super::state::*;
1439 let status_check_timeout =
1440 schedule_association_status_timeout(self.sta.beacon_period(), &mut self.ctx.timer);
1441 let state =
1442 States::from(wlan_statemachine::testing::new_state(Associated(Association {
1443 aid: 42,
1444 assoc_resp_ies: vec![],
1445 controlled_port_open: true,
1446 ap_ht_op: None,
1447 ap_vht_op: None,
1448 qos: Qos::Disabled,
1449 lost_bss_counter: LostBssCounter::start(
1450 self.sta.beacon_period(),
1451 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
1452 ),
1453 status_check_timeout,
1454 signal_strength_average: SignalStrengthAverage::new(),
1455 block_ack_state: StateMachine::new(BlockAckState::from(State::new(Closed))),
1456 })));
1457 self.sta.state.replace(state);
1458 }
1459
1460 async fn close_controlled_port(&mut self) {
1461 self.handle_mlme_req(wlan_sme::MlmeRequest::SetCtrlPort(
1462 fidl_mlme::SetControlledPortRequest {
1463 peer_sta_address: BSSID.to_array(),
1464 state: fidl_mlme::ControlledPortState::Closed,
1465 },
1466 ))
1467 .await;
1468 }
1469 }
1470
1471 #[fuchsia::test(allow_stalls = false)]
1472 async fn spawns_new_sta_on_connect_request_from_sme() {
1473 let mut m = MockObjects::new().await;
1474 let mut me = m.make_mlme().await;
1475 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1476 me.on_sme_connect(fidl_mlme::ConnectRequest {
1477 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
1478 connect_failure_timeout: 100,
1479 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1480 sae_password: vec![],
1481 wep_key: None,
1482 security_ie: vec![],
1483 })
1484 .await
1485 .expect("valid ConnectRequest should be handled successfully");
1486 me.get_bound_client().expect("client sta should have been created by now.");
1487 }
1488
1489 #[fuchsia::test(allow_stalls = false)]
1490 async fn fails_to_connect_if_channel_unknown() {
1491 let mut m = MockObjects::new().await;
1492 let mut me = m.make_mlme().await;
1493 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1494 let mut req = fidl_mlme::ConnectRequest {
1495 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
1496 connect_failure_timeout: 100,
1497 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1498 sae_password: vec![],
1499 wep_key: None,
1500 security_ie: vec![],
1501 };
1502
1503 req.selected_bss.channel.cbw = fidl_fuchsia_wlan_common::ChannelBandwidth::unknown();
1504 me.on_sme_connect(req)
1505 .await
1506 .expect_err("ConnectRequest with unknown channel should be rejected");
1507 assert!(me.get_bound_client().is_none());
1508 }
1509
1510 #[fuchsia::test(allow_stalls = false)]
1511 async fn rsn_ie_implies_sta_eapol_required() {
1512 let mut m = MockObjects::new().await;
1513 let mut me = m.make_mlme().await;
1514 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1515 me.on_sme_connect(fidl_mlme::ConnectRequest {
1516 selected_bss: fake_fidl_bss_description!(Wpa2, ssid: Ssid::try_from("foo").unwrap()),
1517 connect_failure_timeout: 100,
1518 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1519 sae_password: vec![],
1520 wep_key: None,
1521 security_ie: vec![],
1522 })
1523 .await
1524 .expect("valid ConnectRequest should be handled successfully");
1525 let client = me.get_bound_client().expect("client sta should have been created by now.");
1526 assert!(client.sta.eapol_required());
1527 }
1528
1529 #[fuchsia::test(allow_stalls = false)]
1530 async fn wpa1_implies_sta_eapol_required() {
1531 let mut m = MockObjects::new().await;
1532 let mut me = m.make_mlme().await;
1533 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1534 me.on_sme_connect(fidl_mlme::ConnectRequest {
1535 selected_bss: fake_fidl_bss_description!(Wpa1, ssid: Ssid::try_from("foo").unwrap()),
1536 connect_failure_timeout: 100,
1537 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1538 sae_password: vec![],
1539 wep_key: None,
1540 security_ie: vec![],
1541 })
1542 .await
1543 .expect("valid ConnectRequest should be handled successfully");
1544 let client = me.get_bound_client().expect("client sta should have been created by now.");
1545 assert!(client.sta.eapol_required());
1546 }
1547
1548 #[fuchsia::test(allow_stalls = false)]
1549 async fn no_wpa_or_rsn_ie_implies_sta_eapol_not_required() {
1550 let mut m = MockObjects::new().await;
1551 let mut me = m.make_mlme().await;
1552 assert!(me.get_bound_client().is_none(), "MLME should not contain client, yet");
1553 me.on_sme_connect(fidl_mlme::ConnectRequest {
1554 selected_bss: fake_fidl_bss_description!(Open, ssid: Ssid::try_from("foo").unwrap()),
1555 connect_failure_timeout: 100,
1556 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1557 sae_password: vec![],
1558 wep_key: None,
1559 security_ie: vec![],
1560 })
1561 .await
1562 .expect("valid ConnectRequest should be handled successfully");
1563 let client = me.get_bound_client().expect("client sta should have been created by now.");
1564 assert!(!client.sta.eapol_required());
1565 }
1566
1567 async fn handle_association_status_checks_and_signal_reports(
1577 mock_objects: &mut MockObjects,
1578 mlme: &mut ClientMlme<FakeDevice>,
1579 beacon_count: u32,
1580 ) {
1581 for _ in 0..beacon_count / super::state::ASSOCIATION_STATUS_TIMEOUT_BEACON_COUNT {
1582 let (_, timed_event, _) = mock_objects
1583 .time_stream
1584 .try_next()
1585 .unwrap()
1586 .expect("Should have scheduled a timed event");
1587 mlme.handle_timed_event(timed_event.event).await;
1588 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 0);
1589 mock_objects
1590 .fake_device_state
1591 .lock()
1592 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
1593 .expect("error reading SignalReport.indication");
1594 }
1595 }
1596
1597 #[fuchsia::test(allow_stalls = false)]
1598 async fn test_auto_deauth_uninterrupted_interval() {
1599 let mut mock_objects = MockObjects::new().await;
1600 let mut mlme = mock_objects.make_mlme().await;
1601 mlme.make_client_station();
1602 let mut client = mlme.get_bound_client().expect("client should be present");
1603
1604 client.move_to_associated_state();
1605
1606 handle_association_status_checks_and_signal_reports(
1608 &mut mock_objects,
1609 &mut mlme,
1610 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
1611 )
1612 .await;
1613
1614 let (_, timed_event, _) = mock_objects
1616 .time_stream
1617 .try_next()
1618 .unwrap()
1619 .expect("Should have scheduled a timed event");
1620
1621 mlme.handle_timed_event(timed_event.event).await;
1623 mock_objects
1624 .fake_device_state
1625 .lock()
1626 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
1627 .expect("error reading SignalReport.indication");
1628 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
1629 #[rustfmt::skip]
1630 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
1631 0b1100_00_00, 0b00000000, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 3, 0, ][..]);
1640 let deauth_ind = mock_objects
1641 .fake_device_state
1642 .lock()
1643 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
1644 .expect("error reading DEAUTHENTICATE.indication");
1645 assert_eq!(
1646 deauth_ind,
1647 fidl_mlme::DeauthenticateIndication {
1648 peer_sta_address: BSSID.to_array(),
1649 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
1650 locally_initiated: true,
1651 }
1652 );
1653 }
1654
1655 #[fuchsia::test(allow_stalls = false)]
1656 async fn test_auto_deauth_received_beacon() {
1657 let mut mock_objects = MockObjects::new().await;
1658 let mut mlme = mock_objects.make_mlme().await;
1659 mlme.make_client_station();
1660 let mut client = mlme.get_bound_client().expect("client should be present");
1661
1662 client.move_to_associated_state();
1663
1664 handle_association_status_checks_and_signal_reports(
1666 &mut mock_objects,
1667 &mut mlme,
1668 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
1669 )
1670 .await;
1671
1672 mlme.on_mac_frame_rx(
1675 BEACON_FRAME,
1676 fidl_softmac::WlanRxInfo {
1677 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
1678 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
1679 phy: fidl_common::WlanPhyType::Dsss,
1680 data_rate: 0,
1681 channel: mlme.channel_state.get_main_channel().unwrap(),
1682 mcs: 0,
1683 rssi_dbm: 0,
1684 snr_dbh: 0,
1685 },
1686 0.into(),
1687 )
1688 .await;
1689
1690 handle_association_status_checks_and_signal_reports(
1692 &mut mock_objects,
1693 &mut mlme,
1694 DEFAULT_AUTO_DEAUTH_TIMEOUT_BEACON_COUNT,
1695 )
1696 .await;
1697
1698 let (_, timed_event2, _) = mock_objects
1700 .time_stream
1701 .try_next()
1702 .unwrap()
1703 .expect("Should have scheduled a timed event");
1704
1705 mlme.handle_timed_event(timed_event2.event).await;
1707 mock_objects
1708 .fake_device_state
1709 .lock()
1710 .next_mlme_msg::<fidl_internal::SignalReportIndication>()
1711 .expect("error reading SignalReport.indication");
1712 assert_eq!(mock_objects.fake_device_state.lock().wlan_queue.len(), 1);
1713 #[rustfmt::skip]
1714 assert_eq!(&mock_objects.fake_device_state.lock().wlan_queue[0].0[..], &[
1715 0b1100_00_00, 0b00000000, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 3, 0, ][..]);
1724 let deauth_ind = mock_objects
1725 .fake_device_state
1726 .lock()
1727 .next_mlme_msg::<fidl_mlme::DeauthenticateIndication>()
1728 .expect("error reading DEAUTHENTICATE.indication");
1729 assert_eq!(
1730 deauth_ind,
1731 fidl_mlme::DeauthenticateIndication {
1732 peer_sta_address: BSSID.to_array(),
1733 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
1734 locally_initiated: true,
1735 }
1736 );
1737 }
1738
1739 #[fuchsia::test(allow_stalls = false)]
1740 async fn client_send_open_auth_frame() {
1741 let mut m = MockObjects::new().await;
1742 let mut me = m.make_mlme().await;
1743 me.make_client_station();
1744 let mut client = me.get_bound_client().expect("client should be present");
1745 client.send_open_auth_frame().expect("error delivering WLAN frame");
1746 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1747 #[rustfmt::skip]
1748 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1749 0b1011_00_00, 0b00000000, 0, 0, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0x10, 0, 0, 0, 1, 0, 0, 0, ][..]);
1761 }
1762
1763 #[fuchsia::test(allow_stalls = false)]
1764 async fn client_send_assoc_req_frame() {
1765 let mut m = MockObjects::new().await;
1766 let mut me = m.make_mlme().await;
1767 let connect_req = ParsedConnectRequest {
1768 selected_bss: fake_bss_description!(Wpa2,
1769 ssid: Ssid::try_from([11, 22, 33, 44]).unwrap(),
1770 bssid: BSSID.to_array(),
1771 ),
1772 connect_failure_timeout: 100,
1773 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1774 sae_password: vec![],
1775 wep_key: None,
1776 security_ie: RSNE.to_vec(),
1777 };
1778 let client_capabilities = ClientCapabilities(StaCapabilities {
1779 capability_info: CapabilityInfo(0x1234),
1780 rates: vec![8u8, 7, 6, 5, 4, 3, 2, 1, 0].into_iter().map(ie::SupportedRate).collect(),
1781 ht_cap: ie::parse_ht_capabilities(&(0..26).collect::<Vec<u8>>()[..]).map(|h| *h).ok(),
1782 vht_cap: ie::parse_vht_capabilities(&(100..112).collect::<Vec<u8>>()[..])
1783 .map(|v| *v)
1784 .ok(),
1785 });
1786 me.sta.replace(Client::new(connect_req, *IFACE_MAC, client_capabilities));
1787 let mut client = me.get_bound_client().expect("client should be present");
1788 client.send_assoc_req_frame().expect("error delivering WLAN frame");
1789 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1790 assert_eq!(
1791 &m.fake_device_state.lock().wlan_queue[0].0[..],
1792 &[
1793 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, ][..]
1827 );
1828 }
1829
1830 #[fuchsia::test(allow_stalls = false)]
1831 async fn client_send_keep_alive_resp_frame() {
1832 let mut m = MockObjects::new().await;
1833 let mut me = m.make_mlme().await;
1834 me.make_client_station();
1835 let mut client = me.get_bound_client().expect("client should be present");
1836 client.send_keep_alive_resp_frame().expect("error delivering WLAN frame");
1837 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1838 #[rustfmt::skip]
1839 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1840 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, ][..]);
1848 }
1849
1850 #[fuchsia::test(allow_stalls = false)]
1851 async fn client_send_data_frame() {
1852 let payload = vec![5; 8];
1853 let mut m = MockObjects::new().await;
1854 let mut me = m.make_mlme().await;
1855 me.make_client_station();
1856 let mut client = me.get_bound_client().expect("client should be present");
1857 client
1858 .send_data_frame(*IFACE_MAC, [4; 6].into(), false, false, 0x1234, &payload[..], None)
1859 .expect("error delivering WLAN frame");
1860 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1861 #[rustfmt::skip]
1862 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1863 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,
1876 ][..]);
1877 }
1878
1879 #[fuchsia::test(allow_stalls = false)]
1880 async fn client_send_data_frame_ipv4_qos() {
1881 let mut m = MockObjects::new().await;
1882 let mut me = m.make_mlme().await;
1883 let mut client = make_client_station();
1884 client
1885 .bind(&mut me.ctx, &mut me.scanner, &mut me.channel_state)
1886 .send_data_frame(
1887 *IFACE_MAC,
1888 [4; 6].into(),
1889 false,
1890 true,
1891 0x0800, &[1, 0xB0, 3, 4, 5], None,
1894 )
1895 .expect("error delivering WLAN frame");
1896 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1897 #[rustfmt::skip]
1898 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1899 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,
1913 ][..]);
1914 }
1915
1916 #[fuchsia::test(allow_stalls = false)]
1917 async fn client_send_data_frame_ipv6_qos() {
1918 let mut m = MockObjects::new().await;
1919 let mut me = m.make_mlme().await;
1920 let mut client = make_client_station();
1921 client
1922 .bind(&mut me.ctx, &mut me.scanner, &mut me.channel_state)
1923 .send_data_frame(
1924 *IFACE_MAC,
1925 [4; 6].into(),
1926 false,
1927 true,
1928 0x86DD, &[0b0101, 0b10000000, 3, 4, 5], None,
1931 )
1932 .expect("error delivering WLAN frame");
1933 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1934 #[rustfmt::skip]
1935 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1936 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,
1950 ][..]);
1951 }
1952
1953 #[fuchsia::test(allow_stalls = false)]
1954 async fn client_send_data_frame_from_ds() {
1955 let payload = vec![5; 8];
1956 let mut m = MockObjects::new().await;
1957 let mut me = m.make_mlme().await;
1958 me.make_client_station();
1959 let mut client = me.get_bound_client().expect("client should be present");
1960 client
1961 .send_data_frame([3; 6].into(), [4; 6].into(), false, false, 0x1234, &payload[..], None)
1962 .expect("error delivering WLAN frame");
1963 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1964 #[rustfmt::skip]
1965 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1966 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,
1980 ][..]);
1981 }
1982
1983 #[fuchsia::test(allow_stalls = false)]
1984 async fn client_send_deauthentication_notification() {
1985 let mut m = MockObjects::new().await;
1986 let mut me = m.make_mlme().await;
1987 me.make_client_station();
1988 let mut client = me.get_bound_client().expect("client should be present");
1989
1990 client
1991 .send_deauth_frame(fidl_ieee80211::ReasonCode::ApInitiated.into())
1992 .expect("error delivering WLAN frame");
1993 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
1994 #[rustfmt::skip]
1995 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
1996 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, ][..]);
2005 }
2006
2007 fn mock_rx_info<'a>(client: &BoundClient<'a, FakeDevice>) -> fidl_softmac::WlanRxInfo {
2008 let channel = client.channel_state.get_main_channel().unwrap();
2009 MockWlanRxInfo::with_channel(channel).into()
2010 }
2011
2012 #[fuchsia::test(allow_stalls = false)]
2013 async fn respond_to_keep_alive_request() {
2014 #[rustfmt::skip]
2015 let data_frame = vec![
2016 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, ];
2024 let mut m = MockObjects::new().await;
2025 let mut me = m.make_mlme().await;
2026 me.make_client_station();
2027 let mut client = me.get_bound_client().expect("client should be present");
2028 client.move_to_associated_state();
2029
2030 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2031
2032 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2033 #[rustfmt::skip]
2034 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
2035 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, ][..]);
2043 }
2044
2045 #[fuchsia::test(allow_stalls = false)]
2046 async fn data_frame_to_ethernet_single_llc() {
2047 let mut data_frame = make_data_frame_single_llc(None, None);
2048 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;
2053 let mut me = m.make_mlme().await;
2054 me.make_client_station();
2055 let mut client = me.get_bound_client().expect("client should be present");
2056 client.move_to_associated_state();
2057
2058 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2059
2060 assert_eq!(m.fake_device_state.lock().eth_queue.len(), 1);
2061 #[rustfmt::skip]
2062 assert_eq!(m.fake_device_state.lock().eth_queue[0], [
2063 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 9, 10, 11, 11, 11, ]);
2068 }
2069
2070 #[fuchsia::test(allow_stalls = false)]
2071 async fn data_frame_to_ethernet_amsdu() {
2072 let mut data_frame = make_data_frame_amsdu();
2073 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;
2078 let mut me = m.make_mlme().await;
2079 me.make_client_station();
2080 let mut client = me.get_bound_client().expect("client should be present");
2081 client.move_to_associated_state();
2082
2083 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2084
2085 let queue = &m.fake_device_state.lock().eth_queue;
2086 assert_eq!(queue.len(), 2);
2087 #[rustfmt::skip]
2088 let mut expected_first_eth_frame = vec![
2089 0x78, 0x8a, 0x20, 0x0d, 0x67, 0x03, 0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xab, 0x08, 0x00, ];
2093 expected_first_eth_frame.extend_from_slice(MSDU_1_PAYLOAD);
2094 assert_eq!(queue[0], &expected_first_eth_frame[..]);
2095 #[rustfmt::skip]
2096 let mut expected_second_eth_frame = vec![
2097 0x78, 0x8a, 0x20, 0x0d, 0x67, 0x04, 0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xac, 0x08, 0x01, ];
2101 expected_second_eth_frame.extend_from_slice(MSDU_2_PAYLOAD);
2102 assert_eq!(queue[1], &expected_second_eth_frame[..]);
2103 }
2104
2105 #[fuchsia::test(allow_stalls = false)]
2106 async fn data_frame_to_ethernet_amsdu_padding_too_short() {
2107 let mut data_frame = make_data_frame_amsdu_padding_too_short();
2108 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;
2113 let mut me = m.make_mlme().await;
2114 me.make_client_station();
2115 let mut client = me.get_bound_client().expect("client should be present");
2116 client.move_to_associated_state();
2117
2118 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2119
2120 let queue = &m.fake_device_state.lock().eth_queue;
2121 assert_eq!(queue.len(), 1);
2122 #[rustfmt::skip]
2123 let mut expected_first_eth_frame = vec![
2124 0x78, 0x8a, 0x20, 0x0d, 0x67, 0x03, 0xb4, 0xf7, 0xa1, 0xbe, 0xb9, 0xab, 0x08, 0x00, ];
2128 expected_first_eth_frame.extend_from_slice(MSDU_1_PAYLOAD);
2129 assert_eq!(queue[0], &expected_first_eth_frame[..]);
2130 }
2131
2132 #[fuchsia::test(allow_stalls = false)]
2133 async fn data_frame_controlled_port_closed() {
2134 let mut data_frame = make_data_frame_single_llc(None, None);
2135 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;
2140 let mut me = m.make_mlme().await;
2141 me.make_client_station_protected();
2142 let mut client = me.get_bound_client().expect("client should be present");
2143 client.move_to_associated_state();
2144 client.close_controlled_port().await;
2145
2146 client.on_mac_frame(&data_frame[..], mock_rx_info(&client), 0.into()).await;
2147
2148 assert_eq!(m.fake_device_state.lock().eth_queue.len(), 0);
2150 }
2151
2152 #[fuchsia::test(allow_stalls = false)]
2153 async fn eapol_frame_controlled_port_closed() {
2154 let (src_addr, dst_addr, mut eapol_frame) = make_eapol_frame(*IFACE_MAC);
2155 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;
2160 let mut me = m.make_mlme().await;
2161 me.make_client_station_protected();
2162 let mut client = me.get_bound_client().expect("client should be present");
2163 client.move_to_associated_state();
2164 client.close_controlled_port().await;
2165
2166 client.on_mac_frame(&eapol_frame[..], mock_rx_info(&client), 0.into()).await;
2167
2168 assert_eq!(m.fake_device_state.lock().eth_queue.len(), 0);
2170
2171 let eapol_ind = m
2173 .fake_device_state
2174 .lock()
2175 .next_mlme_msg::<fidl_mlme::EapolIndication>()
2176 .expect("error reading EAPOL.indication");
2177 assert_eq!(
2178 eapol_ind,
2179 fidl_mlme::EapolIndication {
2180 src_addr: src_addr.to_array(),
2181 dst_addr: dst_addr.to_array(),
2182 data: EAPOL_PDU.to_vec()
2183 }
2184 );
2185 }
2186
2187 #[fuchsia::test(allow_stalls = false)]
2188 async fn eapol_frame_is_controlled_port_open() {
2189 let (src_addr, dst_addr, mut eapol_frame) = make_eapol_frame(*IFACE_MAC);
2190 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;
2195 let mut me = m.make_mlme().await;
2196 me.make_client_station();
2197 let mut client = me.get_bound_client().expect("client should be present");
2198 client.move_to_associated_state();
2199
2200 client.on_mac_frame(&eapol_frame[..], mock_rx_info(&client), 0.into()).await;
2201
2202 assert_eq!(m.fake_device_state.lock().eth_queue.len(), 0);
2204
2205 let eapol_ind = m
2207 .fake_device_state
2208 .lock()
2209 .next_mlme_msg::<fidl_mlme::EapolIndication>()
2210 .expect("error reading EAPOL.indication");
2211 assert_eq!(
2212 eapol_ind,
2213 fidl_mlme::EapolIndication {
2214 src_addr: src_addr.to_array(),
2215 dst_addr: dst_addr.to_array(),
2216 data: EAPOL_PDU.to_vec()
2217 }
2218 );
2219 }
2220
2221 #[fuchsia::test(allow_stalls = false)]
2222 async fn send_eapol_ind_success() {
2223 let mut m = MockObjects::new().await;
2224 let mut me = m.make_mlme().await;
2225 me.make_client_station();
2226 let mut client = me.get_bound_client().expect("client should be present");
2227 client
2228 .send_eapol_indication([1; 6].into(), [2; 6].into(), &[5; 200])
2229 .expect("expected EAPOL.indication to be sent");
2230 let eapol_ind = m
2231 .fake_device_state
2232 .lock()
2233 .next_mlme_msg::<fidl_mlme::EapolIndication>()
2234 .expect("error reading EAPOL.indication");
2235 assert_eq!(
2236 eapol_ind,
2237 fidl_mlme::EapolIndication {
2238 src_addr: [1; 6].into(),
2239 dst_addr: [2; 6].into(),
2240 data: vec![5; 200]
2241 }
2242 );
2243 }
2244
2245 #[fuchsia::test(allow_stalls = false)]
2246 async fn send_eapol_frame_success() {
2247 let mut m = MockObjects::new().await;
2248 let mut me = m.make_mlme().await;
2249 me.make_client_station();
2250 let mut client = me.get_bound_client().expect("client should be present");
2251 client.send_eapol_frame(*IFACE_MAC, (*BSSID).into(), false, &[5; 8]);
2252
2253 let eapol_confirm = m
2255 .fake_device_state
2256 .lock()
2257 .next_mlme_msg::<fidl_mlme::EapolConfirm>()
2258 .expect("error reading EAPOL.confirm");
2259 assert_eq!(
2260 eapol_confirm,
2261 fidl_mlme::EapolConfirm {
2262 result_code: fidl_mlme::EapolResultCode::Success,
2263 dst_addr: BSSID.to_array(),
2264 }
2265 );
2266
2267 #[rustfmt::skip]
2269 assert_eq!(&m.fake_device_state.lock().wlan_queue[0].0[..], &[
2270 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,
2283 ][..]);
2284 }
2285
2286 #[fuchsia::test(allow_stalls = false)]
2287 async fn send_eapol_frame_failure() {
2288 let mut m = MockObjects::new().await;
2289 m.fake_device_state.lock().config.send_wlan_frame_fails = true;
2290 let mut me = m.make_mlme().await;
2291 me.make_client_station();
2292 let mut client = me.get_bound_client().expect("client should be present");
2293 client.send_eapol_frame([1; 6].into(), [2; 6].into(), false, &[5; 200]);
2294
2295 let eapol_confirm = m
2297 .fake_device_state
2298 .lock()
2299 .next_mlme_msg::<fidl_mlme::EapolConfirm>()
2300 .expect("error reading EAPOL.confirm");
2301 assert_eq!(
2302 eapol_confirm,
2303 fidl_mlme::EapolConfirm {
2304 result_code: fidl_mlme::EapolResultCode::TransmissionFailure,
2305 dst_addr: [2; 6].into(),
2306 }
2307 );
2308
2309 assert!(m.fake_device_state.lock().wlan_queue.is_empty());
2311 }
2312
2313 #[fuchsia::test(allow_stalls = false)]
2314 async fn send_keys() {
2315 let mut m = MockObjects::new().await;
2316 let mut me = m.make_mlme().await;
2317 me.make_client_station_protected();
2318 let mut client = me.get_bound_client().expect("client should be present");
2319 client.move_to_associated_state();
2320
2321 assert!(m.fake_device_state.lock().keys.is_empty());
2322 client.handle_mlme_req(crate::test_utils::fake_set_keys_req((*BSSID).into())).await;
2323 assert_eq!(m.fake_device_state.lock().keys.len(), 1);
2324
2325 let sent_key = crate::test_utils::fake_key((*BSSID).into());
2326 let received_key = &m.fake_device_state.lock().keys[0];
2327 assert_eq!(received_key.key, Some(sent_key.key));
2328 assert_eq!(received_key.key_idx, Some(sent_key.key_id as u8));
2329 assert_eq!(received_key.key_type, Some(fidl_ieee80211::KeyType::Pairwise));
2330 }
2331
2332 #[fuchsia::test(allow_stalls = false)]
2333 async fn send_addba_req_frame() {
2334 let mut mock = MockObjects::new().await;
2335 let mut mlme = mock.make_mlme().await;
2336 mlme.make_client_station();
2337 let mut client = mlme.get_bound_client().expect("client should be present");
2338
2339 let mut body = [0u8; 16];
2340 let mut writer = BufferWriter::new(&mut body[..]);
2341 block_ack::write_addba_req_body(&mut writer, 1).expect("failed writing addba frame");
2342 client
2343 .send_block_ack_frame(ADDBA_REQ_FRAME_LEN, writer.into_written())
2344 .expect("failed sending addba frame");
2345 assert_eq!(
2346 &mock.fake_device_state.lock().wlan_queue[0].0[..],
2347 &[
2348 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, ][..]
2363 );
2364 }
2365
2366 #[fuchsia::test(allow_stalls = false)]
2367 async fn send_addba_resp_frame() {
2368 let mut mock = MockObjects::new().await;
2369 let mut mlme = mock.make_mlme().await;
2370 mlme.make_client_station();
2371 let mut client = mlme.get_bound_client().expect("client should be present");
2372
2373 let mut body = [0u8; 16];
2374 let mut writer = BufferWriter::new(&mut body[..]);
2375 block_ack::write_addba_resp_body(&mut writer, 1).expect("failed writing addba frame");
2376 client
2377 .send_block_ack_frame(ADDBA_RESP_FRAME_LEN, writer.into_written())
2378 .expect("failed sending addba frame");
2379 assert_eq!(
2380 &mock.fake_device_state.lock().wlan_queue[0].0[..],
2381 &[
2382 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, ][..]
2397 );
2398 }
2399
2400 #[fuchsia::test(allow_stalls = false)]
2401 async fn client_send_successful_connect_conf() {
2402 let mut m = MockObjects::new().await;
2403 let mut me = m.make_mlme().await;
2404 me.make_client_station();
2405 let mut client = me.get_bound_client().expect("client should be present");
2406
2407 client.send_connect_conf_success(42, &[0, 5, 3, 4, 5, 6, 7][..]);
2408 let connect_conf = m
2409 .fake_device_state
2410 .lock()
2411 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
2412 .expect("error reading Connect.confirm");
2413 assert_eq!(
2414 connect_conf,
2415 fidl_mlme::ConnectConfirm {
2416 peer_sta_address: BSSID.to_array(),
2417 result_code: fidl_ieee80211::StatusCode::Success,
2418 association_id: 42,
2419 association_ies: vec![0, 5, 3, 4, 5, 6, 7],
2420 }
2421 );
2422 }
2423
2424 #[fuchsia::test(allow_stalls = false)]
2425 async fn client_send_failed_connect_conf() {
2426 let mut m = MockObjects::new().await;
2427 let mut me = m.make_mlme().await;
2428 me.make_client_station();
2429 let mut client = me.get_bound_client().expect("client should be present");
2430 client.send_connect_conf_failure(fidl_ieee80211::StatusCode::DeniedNoMoreStas);
2431 let connect_conf = m
2432 .fake_device_state
2433 .lock()
2434 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
2435 .expect("error reading Connect.confirm");
2436 assert_eq!(
2437 connect_conf,
2438 fidl_mlme::ConnectConfirm {
2439 peer_sta_address: BSSID.to_array(),
2440 result_code: fidl_ieee80211::StatusCode::DeniedNoMoreStas,
2441 association_id: 0,
2442 association_ies: vec![],
2443 }
2444 );
2445 }
2446
2447 #[fuchsia::test(allow_stalls = false)]
2448 async fn client_send_scan_end_on_mlme_scan_busy() {
2449 let mut m = MockObjects::new().await;
2450 let mut me = m.make_mlme().await;
2451 me.make_client_station();
2452
2453 me.on_sme_scan(scan_req()).await;
2455 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
2456
2457 let scan_end = m
2458 .fake_device_state
2459 .lock()
2460 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2461 .expect("error reading MLME ScanEnd");
2462 assert_eq!(
2463 scan_end,
2464 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
2465 );
2466 }
2467
2468 #[fuchsia::test(allow_stalls = false)]
2469 async fn client_send_scan_end_on_scan_busy() {
2470 let mut m = MockObjects::new().await;
2471 let mut me = m.make_mlme().await;
2472 me.make_client_station();
2473
2474 me.on_sme_scan(scan_req()).await;
2476 me.on_sme_scan(fidl_mlme::ScanRequest { txn_id: 1338, ..scan_req() }).await;
2477
2478 let scan_end = m
2479 .fake_device_state
2480 .lock()
2481 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2482 .expect("error reading MLME ScanEnd");
2483 assert_eq!(
2484 scan_end,
2485 fidl_mlme::ScanEnd { txn_id: 1338, code: fidl_mlme::ScanResultCode::NotSupported }
2486 );
2487 }
2488
2489 #[fuchsia::test(allow_stalls = false)]
2490 async fn client_send_scan_end_on_mlme_scan_invalid_args() {
2491 let mut m = MockObjects::new().await;
2492 let mut me = m.make_mlme().await;
2493
2494 me.make_client_station();
2495 me.on_sme_scan(fidl_mlme::ScanRequest {
2496 txn_id: 1337,
2497 scan_type: fidl_mlme::ScanTypes::Passive,
2498 channel_list: vec![], ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
2500 probe_delay: 0,
2501 min_channel_time: 100,
2502 max_channel_time: 300,
2503 })
2504 .await;
2505 let scan_end = m
2506 .fake_device_state
2507 .lock()
2508 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2509 .expect("error reading MLME ScanEnd");
2510 assert_eq!(
2511 scan_end,
2512 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
2513 );
2514 }
2515
2516 #[fuchsia::test(allow_stalls = false)]
2517 async fn client_send_scan_end_on_scan_invalid_args() {
2518 let mut m = MockObjects::new().await;
2519 let mut me = m.make_mlme().await;
2520
2521 me.make_client_station();
2522 me.on_sme_scan(fidl_mlme::ScanRequest {
2523 txn_id: 1337,
2524 scan_type: fidl_mlme::ScanTypes::Passive,
2525 channel_list: vec![6],
2526 ssid_list: vec![Ssid::try_from("ssid").unwrap().into()],
2527 probe_delay: 0,
2528 min_channel_time: 300, max_channel_time: 100,
2530 })
2531 .await;
2532 let scan_end = m
2533 .fake_device_state
2534 .lock()
2535 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2536 .expect("error reading MLME ScanEnd");
2537 assert_eq!(
2538 scan_end,
2539 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::InvalidArgs }
2540 );
2541 }
2542
2543 #[fuchsia::test(allow_stalls = false)]
2544 async fn client_send_scan_end_on_passive_scan_fails() {
2545 let mut m = MockObjects::new().await;
2546 m.fake_device_state.lock().config.start_passive_scan_fails = true;
2547 let mut me = m.make_mlme().await;
2548
2549 me.make_client_station();
2550 me.on_sme_scan(scan_req()).await;
2551 let scan_end = m
2552 .fake_device_state
2553 .lock()
2554 .next_mlme_msg::<fidl_mlme::ScanEnd>()
2555 .expect("error reading MLME ScanEnd");
2556 assert_eq!(
2557 scan_end,
2558 fidl_mlme::ScanEnd { txn_id: 1337, code: fidl_mlme::ScanResultCode::NotSupported }
2559 );
2560 }
2561
2562 #[fuchsia::test(allow_stalls = false)]
2563 async fn mlme_respond_to_query_device_info() {
2564 let mut mock_objects = MockObjects::new().await;
2565 let mut mlme = mock_objects.make_mlme().await;
2566
2567 let (responder, receiver) = Responder::new();
2568 mlme.handle_mlme_req(wlan_sme::MlmeRequest::QueryDeviceInfo(responder))
2569 .await
2570 .expect("Failed to send MlmeRequest::Connect");
2571 assert_eq!(
2572 receiver.await.unwrap(),
2573 fidl_mlme::DeviceInfo {
2574 sta_addr: IFACE_MAC.to_array(),
2575 role: fidl_common::WlanMacRole::Client,
2576 bands: test_utils::fake_mlme_band_caps(),
2577 softmac_hardware_capability: 0,
2578 qos_capable: false,
2579 }
2580 );
2581 }
2582
2583 #[fuchsia::test(allow_stalls = false)]
2584 async fn mlme_respond_to_query_discovery_support() {
2585 let mut m = MockObjects::new().await;
2586 let mut me = m.make_mlme().await;
2587
2588 let (responder, receiver) = Responder::new();
2589 me.handle_mlme_req(wlan_sme::MlmeRequest::QueryDiscoverySupport(responder))
2590 .await
2591 .expect("Failed to send MlmeRequest::Connect");
2592 let resp = receiver.await.unwrap();
2593 assert_eq!(resp.scan_offload.supported, true);
2594 assert_eq!(resp.probe_response_offload.supported, false);
2595 }
2596
2597 #[fuchsia::test(allow_stalls = false)]
2598 async fn mlme_respond_to_query_mac_sublayer_support() {
2599 let mut m = MockObjects::new().await;
2600 let mut me = m.make_mlme().await;
2601
2602 let (responder, receiver) = Responder::new();
2603 me.handle_mlme_req(wlan_sme::MlmeRequest::QueryMacSublayerSupport(responder))
2604 .await
2605 .expect("Failed to send MlmeRequest::Connect");
2606 let resp = receiver.await.unwrap();
2607 assert_eq!(resp.rate_selection_offload.supported, false);
2608 assert_eq!(resp.data_plane.data_plane_type, fidl_common::DataPlaneType::EthernetDevice);
2609 assert_eq!(resp.device.is_synthetic, true);
2610 assert_eq!(
2611 resp.device.mac_implementation_type,
2612 fidl_common::MacImplementationType::Softmac
2613 );
2614 assert_eq!(resp.device.tx_status_report_supported, true);
2615 }
2616
2617 #[fuchsia::test(allow_stalls = false)]
2618 async fn mlme_respond_to_query_security_support() {
2619 let mut m = MockObjects::new().await;
2620 let mut me = m.make_mlme().await;
2621
2622 let (responder, receiver) = Responder::new();
2623 assert_variant!(
2624 me.handle_mlme_req(wlan_sme::MlmeRequest::QuerySecuritySupport(responder)).await,
2625 Ok(())
2626 );
2627 let resp = receiver.await.unwrap();
2628 assert_eq!(resp.mfp.supported, false);
2629 assert_eq!(resp.sae.driver_handler_supported, false);
2630 assert_eq!(resp.sae.sme_handler_supported, false);
2631 }
2632
2633 #[fuchsia::test(allow_stalls = false)]
2634 async fn mlme_respond_to_query_spectrum_management_support() {
2635 let mut m = MockObjects::new().await;
2636 let mut me = m.make_mlme().await;
2637
2638 let (responder, receiver) = Responder::new();
2639 me.handle_mlme_req(wlan_sme::MlmeRequest::QuerySpectrumManagementSupport(responder))
2640 .await
2641 .expect("Failed to send MlmeRequest::QuerySpectrumManagementSupport");
2642 assert_eq!(receiver.await.unwrap().dfs.supported, true);
2643 }
2644
2645 #[fuchsia::test(allow_stalls = false)]
2646 async fn mlme_connect_unprotected_happy_path() {
2647 let mut m = MockObjects::new().await;
2648 let mut me = m.make_mlme().await;
2649 let channel = Channel::new(6, Cbw::Cbw40);
2650 let connect_req = fidl_mlme::ConnectRequest {
2651 selected_bss: fake_fidl_bss_description!(Open,
2652 ssid: Ssid::try_from("ssid").unwrap().into(),
2653 bssid: BSSID.to_array(),
2654 channel: channel.clone(),
2655 ),
2656 connect_failure_timeout: 100,
2657 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
2658 sae_password: vec![],
2659 wep_key: None,
2660 security_ie: vec![],
2661 };
2662 me.handle_mlme_req(wlan_sme::MlmeRequest::Connect(connect_req))
2663 .await
2664 .expect("Failed to send MlmeRequest::Connect");
2665
2666 assert_variant!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
2668 assert_eq!(ids.len(), 1);
2669 });
2670
2671 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2673 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2674 #[rustfmt::skip]
2675 let expected = vec![
2676 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, ];
2688 assert_eq!(&frame[..], &expected[..]);
2689
2690 #[rustfmt::skip]
2692 let auth_resp_success = vec![
2693 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, ];
2705 me.on_mac_frame_rx(
2706 &auth_resp_success[..],
2707 MockWlanRxInfo::with_channel(channel.into()).into(),
2708 0.into(),
2709 )
2710 .await;
2711
2712 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2714 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2715 #[rustfmt::skip]
2716 let expected = vec![
2717 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, ];
2739 assert_eq!(&frame[..], &expected[..]);
2740
2741 #[rustfmt::skip]
2743 let assoc_resp_success = vec![
2744 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,
2758 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2762 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ];
2766 me.on_mac_frame_rx(
2767 &assoc_resp_success[..],
2768 MockWlanRxInfo::with_channel(channel.into()).into(),
2769 0.into(),
2770 )
2771 .await;
2772
2773 let msg = m
2775 .fake_device_state
2776 .lock()
2777 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
2778 .expect("expect ConnectConf");
2779 assert_eq!(
2780 msg,
2781 fidl_mlme::ConnectConfirm {
2782 peer_sta_address: BSSID.to_array(),
2783 result_code: fidl_ieee80211::StatusCode::Success,
2784 association_id: 42,
2785 association_ies: vec![
2786 0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
2789 0x2d, 0x1a, 0xef, 0x09, 0x17, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2793 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
2797 }
2798 );
2799
2800 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
2802 }
2803
2804 #[fuchsia::test(allow_stalls = false)]
2805 async fn mlme_connect_protected_happy_path() {
2806 let mut m = MockObjects::new().await;
2807 let mut me = m.make_mlme().await;
2808 let channel = Channel::new(6, Cbw::Cbw40);
2809 let connect_req = fidl_mlme::ConnectRequest {
2810 selected_bss: fake_fidl_bss_description!(Wpa2,
2811 ssid: Ssid::try_from("ssid").unwrap().into(),
2812 bssid: BSSID.to_array(),
2813 channel: channel.clone(),
2814 ),
2815 connect_failure_timeout: 100,
2816 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
2817 sae_password: vec![],
2818 wep_key: None,
2819 security_ie: vec![
2820 48, 18, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 4, 1, 0, 0x00, 0x0F, 0xAC, 2, ],
2826 };
2827 me.handle_mlme_req(wlan_sme::MlmeRequest::Connect(connect_req))
2828 .await
2829 .expect("Failed to send MlmeRequest::Connect");
2830
2831 assert_variant!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
2833 assert_eq!(ids.len(), 1);
2834 });
2835
2836 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2838 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2839 #[rustfmt::skip]
2840 let expected = vec![
2841 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, ];
2853 assert_eq!(&frame[..], &expected[..]);
2854
2855 #[rustfmt::skip]
2857 let auth_resp_success = vec![
2858 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, ];
2870 me.on_mac_frame_rx(
2871 &auth_resp_success[..],
2872 MockWlanRxInfo::with_channel(channel.into()).into(),
2873 0.into(),
2874 )
2875 .await;
2876
2877 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
2879 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
2880 #[rustfmt::skip]
2881 let expected = vec![
2882 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, ];
2909 assert_eq!(&frame[..], &expected[..]);
2910
2911 #[rustfmt::skip]
2913 let assoc_resp_success = vec![
2914 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,
2928 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, ];
2941 me.on_mac_frame_rx(
2942 &assoc_resp_success[..],
2943 MockWlanRxInfo::with_channel(channel.into()).into(),
2944 0.into(),
2945 )
2946 .await;
2947
2948 let msg = m
2950 .fake_device_state
2951 .lock()
2952 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
2953 .expect("expect ConnectConf");
2954 assert_eq!(
2955 msg,
2956 fidl_mlme::ConnectConfirm {
2957 peer_sta_address: BSSID.to_array(),
2958 result_code: fidl_ieee80211::StatusCode::Success,
2959 association_id: 42,
2960 association_ies: vec![
2961 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,
2972 0x00, 0x00, 0xbf, 0x0c, 0x91, 0x59, 0x82, 0x0f, 0xea, 0xff, 0x00, 0x00, 0xea, 0xff, 0x00, 0x00, ],
2977 }
2978 );
2979
2980 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::DOWN);
2982
2983 me.handle_mlme_req(wlan_sme::MlmeRequest::SetCtrlPort(
2985 fidl_mlme::SetControlledPortRequest {
2986 peer_sta_address: BSSID.to_array(),
2987 state: fidl_mlme::ControlledPortState::Open,
2988 },
2989 ))
2990 .await
2991 .expect("expect sending msg to succeed");
2992
2993 assert_eq!(m.fake_device_state.lock().link_status, LinkStatus::UP);
2995 }
2996
2997 #[fuchsia::test(allow_stalls = false)]
2998 async fn mlme_connect_vht() {
2999 let mut m = MockObjects::new().await;
3000 let mut me = m.make_mlme().await;
3001 let channel = Channel::new(36, Cbw::Cbw40);
3002 let connect_req = fidl_mlme::ConnectRequest {
3003 selected_bss: fake_fidl_bss_description!(Open,
3004 ssid: Ssid::try_from("ssid").unwrap().into(),
3005 bssid: BSSID.to_array(),
3006 channel: channel.clone(),
3007 ),
3008 connect_failure_timeout: 100,
3009 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
3010 sae_password: vec![],
3011 wep_key: None,
3012 security_ie: vec![],
3013 };
3014 me.handle_mlme_req(wlan_sme::MlmeRequest::Connect(connect_req))
3015 .await
3016 .expect("Failed to send MlmeRequest::Connect.");
3017
3018 assert_variant!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(ids) => {
3020 assert_eq!(ids.len(), 1);
3021 });
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
3027 #[rustfmt::skip]
3029 let auth_resp_success = vec![
3030 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, ];
3042 me.on_mac_frame_rx(
3043 &auth_resp_success[..],
3044 MockWlanRxInfo::with_channel(channel.into()).into(),
3045 0.into(),
3046 )
3047 .await;
3048
3049 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
3051 let (frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
3052 #[rustfmt::skip]
3053 let expected = vec![
3054 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, ];
3076 assert_eq!(&frame[..], &expected[..]);
3077 }
3078
3079 #[fuchsia::test(allow_stalls = false)]
3080 async fn mlme_connect_timeout() {
3081 let mut m = MockObjects::new().await;
3082 let mut me = m.make_mlme().await;
3083 let connect_req = fidl_mlme::ConnectRequest {
3084 selected_bss: fake_fidl_bss_description!(Open, bssid: BSSID.to_array()),
3085 connect_failure_timeout: 100,
3086 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
3087 sae_password: vec![],
3088 wep_key: None,
3089 security_ie: vec![],
3090 };
3091 me.handle_mlme_req(wlan_sme::MlmeRequest::Connect(connect_req))
3092 .await
3093 .expect("Failed to send MlmeRequest::Connect.");
3094
3095 let (event, _id) = assert_variant!(drain_timeouts(&mut m.time_stream).get(&TimedEventClass::Connecting), Some(events) => {
3097 assert_eq!(events.len(), 1);
3098 events[0].clone()
3099 });
3100
3101 assert_eq!(m.fake_device_state.lock().wlan_queue.len(), 1);
3103 let (_frame, _txflags) = m.fake_device_state.lock().wlan_queue.remove(0);
3104
3105 me.handle_timed_event(event).await;
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: BSSID.to_array(),
3118 result_code: fidl_ieee80211::StatusCode::RejectedSequenceTimeout,
3119 association_id: 0,
3120 association_ies: vec![],
3121 },
3122 );
3123 }
3124
3125 #[fuchsia::test(allow_stalls = false)]
3126 async fn mlme_reconnect_no_sta() {
3127 let mut m = MockObjects::new().await;
3128 let mut me = m.make_mlme().await;
3129
3130 let reconnect_req = fidl_mlme::ReconnectRequest { peer_sta_address: [1, 2, 3, 4, 5, 6] };
3131 let result = me.handle_mlme_req(wlan_sme::MlmeRequest::Reconnect(reconnect_req)).await;
3132 assert_variant!(result, Err(Error::Status(_, zx::Status::BAD_STATE)));
3133
3134 let msg = m
3136 .fake_device_state
3137 .lock()
3138 .next_mlme_msg::<fidl_mlme::ConnectConfirm>()
3139 .expect("expect msg");
3140 assert_eq!(
3141 msg,
3142 fidl_mlme::ConnectConfirm {
3143 peer_sta_address: [1, 2, 3, 4, 5, 6],
3144 result_code: fidl_ieee80211::StatusCode::DeniedNoAssociationExists,
3145 association_id: 0,
3146 association_ies: vec![],
3147 },
3148 );
3149 }
3150
3151 #[fuchsia::test(allow_stalls = false)]
3152 async fn mlme_respond_to_get_iface_stats_with_error_status() {
3153 let mut m = MockObjects::new().await;
3154 let mut me = m.make_mlme().await;
3155
3156 let (responder, receiver) = Responder::new();
3157 me.handle_mlme_req(wlan_sme::MlmeRequest::GetIfaceStats(responder))
3158 .await
3159 .expect("Failed to send MlmeRequest::GetIfaceStats.");
3160 assert_eq!(
3161 receiver.await,
3162 Ok(fidl_mlme::GetIfaceStatsResponse::ErrorStatus(zx::sys::ZX_ERR_NOT_SUPPORTED))
3163 );
3164 }
3165
3166 #[fuchsia::test(allow_stalls = false)]
3167 async fn mlme_respond_to_get_iface_histogram_stats_with_error_status() {
3168 let mut m = MockObjects::new().await;
3169 let mut me = m.make_mlme().await;
3170
3171 let (responder, receiver) = Responder::new();
3172 me.handle_mlme_req(wlan_sme::MlmeRequest::GetIfaceHistogramStats(responder))
3173 .await
3174 .expect("Failed to send MlmeRequest::GetIfaceHistogramStats");
3175 assert_eq!(
3176 receiver.await,
3177 Ok(fidl_mlme::GetIfaceHistogramStatsResponse::ErrorStatus(
3178 zx::sys::ZX_ERR_NOT_SUPPORTED
3179 ))
3180 );
3181 }
3182
3183 #[test]
3184 fn drop_mgmt_frame_wrong_bssid() {
3185 let frame = [
3186 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0x10, 0, ];
3194 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3195 assert_eq!(false, make_client_station().should_handle_frame(&frame));
3196 }
3197
3198 #[test]
3199 fn drop_mgmt_frame_wrong_dst_addr() {
3200 let frame = [
3201 0b11010000, 0b00000000, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3209 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3210 assert_eq!(false, make_client_station().should_handle_frame(&frame));
3211 }
3212
3213 #[test]
3214 fn mgmt_frame_ok_broadcast() {
3215 let frame = [
3216 0b11010000, 0b00000000, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3224 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3225 assert_eq!(true, make_client_station().should_handle_frame(&frame));
3226 }
3227
3228 #[test]
3229 fn mgmt_frame_ok_client_addr() {
3230 let frame = [
3231 0b11010000, 0b00000000, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3239 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3240 assert_eq!(true, make_client_station().should_handle_frame(&frame));
3241 }
3242
3243 #[test]
3244 fn drop_data_frame_wrong_bssid() {
3245 let frame = [
3246 0b01001000,
3248 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3255 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3256 assert_eq!(false, make_client_station().should_handle_frame(&frame));
3257 }
3258
3259 #[test]
3260 fn drop_data_frame_wrong_dst_addr() {
3261 let frame = [
3262 0b01001000,
3264 0b00000010, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3271 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3272 assert_eq!(false, make_client_station().should_handle_frame(&frame));
3273 }
3274
3275 #[test]
3276 fn data_frame_ok_broadcast() {
3277 let frame = [
3278 0b01001000,
3280 0b00000010, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3287 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3288 assert_eq!(true, make_client_station().should_handle_frame(&frame));
3289 }
3290
3291 #[test]
3292 fn data_frame_ok_client_addr() {
3293 let frame = [
3294 0b01001000,
3296 0b00000010, 0, 0, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0x10, 0, ];
3303 let frame = mac::MacFrame::parse(&frame[..], false).unwrap();
3304 assert_eq!(true, make_client_station().should_handle_frame(&frame));
3305 }
3306}