1mod context;
6mod frame_writer;
7mod infra_bss;
8mod remote_client;
9
10use crate::ddk_converter;
11use crate::device::{self, DeviceOps};
12use crate::error::Error;
13use fdf::ArenaStaticBox;
14use fidl_fuchsia_wlan_common as fidl_common;
15use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
16use fidl_fuchsia_wlan_minstrel as fidl_minstrel;
17use fidl_fuchsia_wlan_mlme as fidl_mlme;
18use fidl_fuchsia_wlan_softmac as fidl_softmac;
19use fuchsia_trace as trace;
20use ieee80211::{Bssid, MacAddr, Ssid};
21use log::{debug, error, info, trace, warn};
22use std::fmt;
23use wlan_common::TimeUnit;
24use wlan_common::channel::{Cbw, Channel};
25use wlan_common::mac::{self, CapabilityInfo};
26use wlan_common::timer::Timer;
27use wlan_trace as wtrace;
28use zerocopy::SplitByteSlice;
29
30use context::*;
31use infra_bss::*;
32use remote_client::*;
33
34#[derive(Debug)]
35struct BufferedFrame {
36 buffer: ArenaStaticBox<[u8]>,
37 tx_flags: fidl_softmac::WlanTxInfoFlags,
38 async_id: trace::Id,
39}
40
41#[derive(Debug)]
43pub enum Rejection {
44 OtherBss,
46
47 BadDsBits,
51
52 FrameMalformed,
56
57 NoSrcAddr,
59
60 NoSuchClient(MacAddr),
62
63 Client(MacAddr, ClientRejection),
65
66 Error(anyhow::Error),
68}
69
70impl Rejection {
71 fn log_level(&self) -> log::Level {
72 match self {
73 Self::NoSrcAddr | Self::FrameMalformed => log::Level::Error,
74 Self::Client(_, e) => e.log_level(),
75 _ => log::Level::Trace,
76 }
77 }
78 fn log(&self, msg: &str) {
79 match self.log_level() {
80 log::Level::Trace => trace!("{}: {}", msg, self),
81 log::Level::Debug => debug!("{}: {}", msg, self),
82 log::Level::Info => info!("{}: {}", msg, self),
83 log::Level::Warn => warn!("{}: {}", msg, self),
84 log::Level::Error => error!("{}: {}", msg, self),
85 }
86 }
87}
88
89impl fmt::Display for Rejection {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 match self {
92 Self::Client(addr, e) => write!(f, "client {:02X?}: {:?}", addr, e),
93 _ => fmt::Debug::fmt(self, f),
94 }
95 }
96}
97
98impl From<anyhow::Error> for Rejection {
99 fn from(e: anyhow::Error) -> Rejection {
100 Self::Error(e)
101 }
102}
103
104#[derive(Debug)]
105pub enum TimedEvent {
106 ClientEvent(MacAddr, ClientEvent),
108}
109
110pub struct Ap<D> {
111 ctx: Context<D>,
112 bss: Option<InfraBss>,
113}
114
115trait BssOptionExt<T: std::borrow::Borrow<InfraBss>> {
118 fn ok_or_bss_err(self) -> Result<T, Error>;
119}
120
121impl<T: std::borrow::Borrow<InfraBss>> BssOptionExt<T> for Option<T> {
122 fn ok_or_bss_err(self) -> Result<T, Error> {
123 self.ok_or(Error::Status(format!("BSS not started"), zx::Status::BAD_STATE))
124 }
125}
126
127impl<D: DeviceOps> crate::MlmeImpl for Ap<D> {
128 type Config = Bssid;
129 type Device = D;
130 type TimerEvent = TimedEvent;
131
132 async fn new(
133 config: Self::Config,
134 device: D,
135 timer: Timer<TimedEvent>,
136 ) -> Result<Self, anyhow::Error>
137 where
138 Self: Sized,
139 {
140 Ok(Self::new(device, timer, config))
141 }
142 async fn handle_mlme_request(
143 &mut self,
144 req: wlan_sme::MlmeRequest,
145 ) -> Result<(), anyhow::Error> {
146 Self::handle_mlme_req(self, req).await.map_err(|e| e.into())
147 }
148 async fn handle_mac_frame_rx(
149 &mut self,
150 frame: &[u8],
151 rx_info: fidl_softmac::WlanRxInfo,
152 async_id: trace::Id,
153 ) {
154 Self::handle_mac_frame_rx(self, frame, rx_info, async_id).await
155 }
156 fn handle_eth_frame_tx(
157 &mut self,
158 bytes: &[u8],
159 async_id: trace::Id,
160 ) -> Result<(), anyhow::Error> {
161 Self::handle_eth_frame_tx(self, bytes, async_id);
162 Ok(())
163 }
164 async fn handle_scan_complete(&mut self, _status: zx::Status, _scan_id: u64) {
165 warn!("Unexpected ScanComplete for AP MLME.");
166 return;
167 }
168 async fn handle_timeout(&mut self, event: TimedEvent) {
169 Self::handle_timed_event(self, event).await
170 }
171}
172
173impl<D> Ap<D> {
174 pub fn new(device: D, timer: Timer<TimedEvent>, bssid: Bssid) -> Self {
175 Self { ctx: Context::new(device, timer, bssid), bss: None }
176 }
177
178 fn handle_sme_list_minstrel_peers(
179 &self,
180 responder: wlan_sme::responder::Responder<fidl_mlme::MinstrelListResponse>,
181 ) -> Result<(), Error> {
182 error!("ListMinstrelPeers is not supported.");
184 let peers = fidl_minstrel::Peers { addrs: vec![] };
185 let resp = fidl_mlme::MinstrelListResponse { peers };
186 responder.respond(resp);
187 Ok(())
188 }
189
190 fn handle_sme_get_minstrel_stats(
191 &self,
192 responder: wlan_sme::responder::Responder<fidl_mlme::MinstrelStatsResponse>,
193 _addr: &MacAddr,
194 ) -> Result<(), Error> {
195 error!("GetMinstrelStats is not supported.");
197 let resp = fidl_mlme::MinstrelStatsResponse { peer: None };
198 responder.respond(resp);
199 Ok(())
200 }
201}
202
203impl<D: DeviceOps> Ap<D> {
204 pub async fn handle_timed_event(&mut self, event: TimedEvent) {
206 let bss = match self.bss.as_mut() {
207 Some(bss) => bss,
208 None => {
209 error!("received timed event but BSS was not started yet");
210 return;
211 }
212 };
213
214 if let Err(e) = bss.handle_timed_event(&mut self.ctx, event).await {
215 error!("failed to handle timed event frame: {}", e)
216 }
217 }
218
219 async fn handle_mlme_start_req(&mut self, req: fidl_mlme::StartRequest) -> Result<(), Error> {
223 if self.bss.is_some() {
224 info!("MLME-START.request: BSS already started");
225 self.ctx.send_mlme_start_conf(fidl_mlme::StartResultCode::BssAlreadyStartedOrJoined)?;
226 return Ok(());
227 }
228
229 if req.bss_type != fidl_ieee80211::BssType::Infrastructure {
230 info!("MLME-START.request: BSS type {:?} not supported", req.bss_type);
231 self.ctx.send_mlme_start_conf(fidl_mlme::StartResultCode::NotSupported)?;
232 return Ok(());
233 }
234
235 let cbw = Cbw::from_fidl(req.bandwidth, 0).map_err(|e| {
236 Error::Status(format!("failed to parse cbw: {}", e), zx::Status::INVALID_ARGS)
237 })?;
238 let channel = Channel::new(req.primary.number, cbw, req.primary.band);
239 self.bss.replace(
240 InfraBss::new(
241 &mut self.ctx,
242 Ssid::from_bytes_unchecked(req.ssid),
243 TimeUnit(req.beacon_period),
244 req.dtim_period,
245 CapabilityInfo(req.capability_info),
246 req.rates,
247 channel.primary,
248 channel.band,
249 req.rsne,
250 )
251 .await?,
252 );
253
254 self.ctx.send_mlme_start_conf(fidl_mlme::StartResultCode::Success)?;
255
256 info!("MLME-START.request: OK");
257 Ok(())
258 }
259
260 async fn handle_mlme_stop_req(&mut self, _req: fidl_mlme::StopRequest) -> Result<(), Error> {
262 match self.bss.take() {
263 Some(bss) => match bss.stop(&mut self.ctx).await {
264 Ok(_) => self.ctx.send_mlme_stop_conf(fidl_mlme::StopResultCode::Success)?,
265 Err(e) => {
266 self.ctx.send_mlme_stop_conf(fidl_mlme::StopResultCode::InternalError)?;
267 return Err(e);
268 }
269 },
270 None => {
271 info!("MLME-STOP.request: BSS not started");
272 self.ctx.send_mlme_stop_conf(fidl_mlme::StopResultCode::BssAlreadyStopped)?;
273 }
274 }
275 info!("MLME-STOP.request: OK");
276 Ok(())
277 }
278
279 pub async fn handle_mlme_setkeys_req(
283 &mut self,
284 req: fidl_mlme::SetKeysRequest,
285 ) -> Result<(), Error> {
286 if let Some(bss) = self.bss.as_mut() {
287 bss.handle_mlme_setkeys_req(&mut self.ctx, req.keylist).await
288 } else {
289 Err(Error::Status(format!("cannot set keys on unstarted BSS"), zx::Status::BAD_STATE))
290 }
291 }
292
293 pub async fn handle_mlme_query_device_info(
294 &mut self,
295 responder: wlan_sme::responder::Responder<fidl_mlme::DeviceInfo>,
296 ) -> Result<(), Error> {
297 let info = ddk_converter::mlme_device_info_from_softmac(
298 device::try_query(&mut self.ctx.device).await?,
299 )?;
300 responder.respond(info);
301 Ok(())
302 }
303
304 pub async fn handle_mlme_query_mac_sublayer_support(
305 &mut self,
306 responder: wlan_sme::responder::Responder<fidl_common::MacSublayerSupport>,
307 ) -> Result<(), Error> {
308 let support = device::try_query_mac_sublayer_support(&mut self.ctx.device).await?;
309 responder.respond(support);
310 Ok(())
311 }
312
313 pub async fn handle_mlme_query_security_support(
314 &mut self,
315 responder: wlan_sme::responder::Responder<fidl_common::SecuritySupport>,
316 ) -> Result<(), Error> {
317 let support = device::try_query_security_support(&mut self.ctx.device).await?;
318 responder.respond(support);
319 Ok(())
320 }
321
322 pub async fn handle_mlme_query_spectrum_management_support(
323 &mut self,
324 responder: wlan_sme::responder::Responder<fidl_common::SpectrumManagementSupport>,
325 ) -> Result<(), Error> {
326 let support = device::try_query_spectrum_management_support(&mut self.ctx.device).await?;
327 responder.respond(support);
328 Ok(())
329 }
330
331 pub async fn handle_mlme_req(&mut self, req: wlan_sme::MlmeRequest) -> Result<(), Error> {
332 use wlan_sme::MlmeRequest as Req;
333 match req {
334 Req::Start(req) => self.handle_mlme_start_req(req).await,
335 Req::Stop(req) => self.handle_mlme_stop_req(req).await,
336 Req::SetKeys(req) => self.handle_mlme_setkeys_req(req).await,
337 Req::QueryDeviceInfo(responder) => self.handle_mlme_query_device_info(responder).await,
338 Req::QueryMacSublayerSupport(responder) => {
339 self.handle_mlme_query_mac_sublayer_support(responder).await
340 }
341 Req::QuerySecuritySupport(responder) => {
342 self.handle_mlme_query_security_support(responder).await
343 }
344 Req::QuerySpectrumManagementSupport(responder) => {
345 self.handle_mlme_query_spectrum_management_support(responder).await
346 }
347 Req::ListMinstrelPeers(responder) => self.handle_sme_list_minstrel_peers(responder),
348 Req::GetMinstrelStats(req, responder) => {
349 self.handle_sme_get_minstrel_stats(responder, &req.peer_addr.into())
350 }
351 Req::AuthResponse(resp) => {
352 info!("Handling MLME auth resp. self.bss.is_some()?: {}", self.bss.is_some());
354 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_auth_resp(&mut self.ctx, resp).await
355 }
356 Req::Deauthenticate(req) => {
357 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_deauth_req(&mut self.ctx, req).await
358 }
359 Req::AssocResponse(resp) => {
360 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_assoc_resp(&mut self.ctx, resp).await
361 }
362 Req::Disassociate(req) => {
363 self.bss
364 .as_mut()
365 .ok_or_bss_err()?
366 .handle_mlme_disassoc_req(&mut self.ctx, req)
367 .await
368 }
369 Req::SetCtrlPort(req) => {
370 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_set_controlled_port_req(req)
371 }
372 Req::Eapol(req) => {
373 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_eapol_req(&mut self.ctx, req)
374 }
375 _ => Err(Error::Status(format!("not supported"), zx::Status::NOT_SUPPORTED)),
376 }
377 .map_err(|e| {
378 error!("error handling MLME message: {}", e);
379 e
380 })
381 }
382
383 pub fn handle_eth_frame_tx(&mut self, frame: &[u8], async_id: trace::Id) {
384 let bss = match self.bss.as_mut() {
385 Some(bss) => bss,
386 None => {
387 error!("received Ethernet frame but BSS was not started yet");
388 return;
389 }
390 };
391
392 let mac::EthernetFrame { hdr, body } =
393 match mac::EthernetFrame::parse(frame).ok_or_else(|| Rejection::FrameMalformed) {
394 Ok(eth_frame) => eth_frame,
395 Err(e) => {
396 error!("failed to parse Ethernet frame: {}", e);
397 return;
398 }
399 };
400
401 if let Err(e) = bss.handle_eth_frame(&mut self.ctx, *hdr, body, async_id) {
402 e.log("failed to handle Ethernet frame")
403 }
404 }
405
406 pub async fn handle_mac_frame_rx<B: SplitByteSlice>(
407 &mut self,
408 bytes: B,
409 rx_info: fidl_softmac::WlanRxInfo,
410 async_id: trace::Id,
411 ) {
412 let bss = match self.bss.as_mut() {
413 Some(bss) => bss,
414 None => {
415 error!("received WLAN frame but BSS was not started yet");
416 wtrace::async_end_wlansoftmac_rx(async_id, "BSS not started");
417 return;
418 }
419 };
420
421 if rx_info.primary.number != bss.channel {
423 wtrace::async_end_wlansoftmac_rx(async_id, "frame from wrong channel");
424 return;
425 }
426
427 let body_aligned = (rx_info.rx_flags & fidl_softmac::WlanRxInfoFlags::FRAME_BODY_PADDING_4)
428 != fidl_softmac::WlanRxInfoFlags::empty();
429
430 let mac_frame = match mac::MacFrame::parse(bytes, body_aligned) {
431 Some(mac_frame) => mac_frame,
432 None => {
433 error!("failed to parse MAC frame");
434 wtrace::async_end_wlansoftmac_rx(async_id, "failed to parse frame");
435 return;
436 }
437 };
438
439 if let Err(e) = match mac_frame {
440 mac::MacFrame::Mgmt(mgmt) => bss.handle_mgmt_frame(&mut self.ctx, mgmt).await,
441 mac::MacFrame::Data(data_frame) => bss.handle_data_frame(&mut self.ctx, data_frame),
442 mac::MacFrame::Ctrl(ctrl_frame) => bss.handle_ctrl_frame(&mut self.ctx, ctrl_frame),
443 mac::MacFrame::Unsupported { frame_ctrl } => {
444 error!("received unsupported MAC frame: frame_ctrl = {:?}", frame_ctrl);
445 wtrace::async_end_wlansoftmac_rx(async_id, "received unsupported frame");
446 return;
447 }
448 } {
449 wtrace::async_end_wlansoftmac_rx(async_id, "failed to handle frame");
450 e.log("failed to handle MAC frame")
451 } else {
452 wtrace::async_end_wlansoftmac_rx(async_id, "successfully handled frame");
453 }
454 }
455}
456
457#[cfg(test)]
458mod tests {
459 use super::*;
460 use crate::device::{FakeDevice, FakeDeviceConfig, FakeDeviceState, LinkStatus, test_utils};
461 use crate::test_utils::MockWlanRxInfo;
462 use assert_matches::assert_matches;
463 use fidl_fuchsia_wlan_common as fidl_common;
464 use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
465 use fidl_fuchsia_wlan_ieee80211::WlanBand::TwoGhz;
466 use fidl_fuchsia_wlan_softmac as fidl_softmac;
467 use fuchsia_sync::Mutex;
468 use ieee80211::MacAddrBytes;
469 use std::sync::{Arc, LazyLock};
470 use wlan_common::test_utils::fake_frames::fake_wpa2_rsne;
471 use wlan_common::timer;
472 use wlan_frame_writer::write_frame_to_vec;
473 use wlan_sme::responder::Responder;
474 use zerocopy::byteorder::big_endian::U16 as BigEndianU16;
475
476 static CLIENT_ADDR: LazyLock<MacAddr> = LazyLock::new(|| [4u8; 6].into());
477 static BSSID: LazyLock<Bssid> = LazyLock::new(|| [2u8; 6].into());
478 static CLIENT_ADDR2: LazyLock<MacAddr> = LazyLock::new(|| [6u8; 6].into());
479
480 fn make_eth_frame(
481 dst_addr: MacAddr,
482 src_addr: MacAddr,
483 protocol_id: u16,
484 body: &[u8],
485 ) -> Vec<u8> {
486 write_frame_to_vec!({
487 headers: {
488 mac::EthernetIIHdr: &mac::EthernetIIHdr {
489 da: dst_addr,
490 sa: src_addr,
491 ether_type: BigEndianU16::new(protocol_id),
492 },
493 },
494 payload: body,
495 })
496 .unwrap() }
498
499 async fn make_ap()
503 -> (Ap<FakeDevice>, Arc<Mutex<FakeDeviceState>>, timer::EventStream<TimedEvent>) {
504 let (timer, time_stream) = timer::create_timer();
505 let (fake_device, fake_device_state) = FakeDevice::new_with_config(
506 FakeDeviceConfig::default()
507 .with_mock_mac_role(fidl_common::WlanMacRole::Ap)
508 .with_mock_sta_addr((*BSSID).to_array()),
509 )
510 .await;
511 (Ap::new(fake_device, timer, *BSSID), fake_device_state, time_stream)
512 }
513
514 async fn make_infra_bss(ctx: &mut Context<FakeDevice>, protected: bool) -> InfraBss {
515 InfraBss::new(
516 ctx,
517 Ssid::try_from("coolnet").unwrap(),
518 TimeUnit::DEFAULT_BEACON_INTERVAL,
519 2,
520 CapabilityInfo(0),
521 vec![0b11111000],
522 1,
523 TwoGhz,
524 match protected {
525 false => None,
526 true => Some(fake_wpa2_rsne()),
527 },
528 )
529 .await
530 .expect("expected InfraBss::new ok")
531 }
532
533 #[fuchsia::test(allow_stalls = false)]
534 async fn ap_handle_eth_frame() {
535 let (mut ap, fake_device_state, _) = make_ap().await;
536 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
537 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
538
539 let client = ap.bss.as_mut().unwrap().clients.get_mut(&CLIENT_ADDR).unwrap();
540 client
541 .handle_mlme_auth_resp(&mut ap.ctx, fidl_mlme::AuthenticateResultCode::Success)
542 .await
543 .expect("expected OK");
544 client
545 .handle_mlme_assoc_resp(
546 &mut ap.ctx,
547 false,
548 fidl_ieee80211::ChannelNumber { number: 1, band: TwoGhz },
549 mac::CapabilityInfo(0),
550 fidl_mlme::AssociateResultCode::Success,
551 1,
552 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
553 )
554 .await
555 .expect("expected OK");
556 fake_device_state.lock().wlan_queue.clear();
557
558 ap.handle_eth_frame_tx(
559 &make_eth_frame(*CLIENT_ADDR, *CLIENT_ADDR2, 0x1234, &[1, 2, 3, 4, 5][..]),
560 0.into(),
561 );
562
563 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
564 assert_eq!(
565 &fake_device_state.lock().wlan_queue[0].0[..],
566 &[
567 0b00001000, 0b00000010, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 0x30, 0, 0xAA, 0xAA, 0x03, 0, 0, 0, 0x12, 0x34, 1, 2, 3, 4, 5,
579 ][..]
580 );
581 }
582
583 #[fuchsia::test(allow_stalls = false)]
584 async fn ap_handle_eth_frame_no_such_client() {
585 let (mut ap, _, _) = make_ap().await;
586 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
587 ap.handle_eth_frame_tx(
588 &make_eth_frame(*CLIENT_ADDR2, *CLIENT_ADDR, 0x1234, &[1, 2, 3, 4, 5][..]),
589 0.into(),
590 );
591 }
592
593 fn mock_rx_info(ap: &Ap<FakeDevice>) -> fidl_softmac::WlanRxInfo {
594 let channel = fidl_ieee80211::ChannelNumber {
595 band: fidl_ieee80211::WlanBand::TwoGhz,
596 number: ap.bss.as_ref().unwrap().channel,
597 };
598 MockWlanRxInfo::with_channel(channel).into()
599 }
600
601 #[fuchsia::test(allow_stalls = false)]
602 async fn ap_handle_mac_frame() {
603 let (mut ap, fake_device_state, _) = make_ap().await;
604 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
605 ap.handle_mac_frame_rx(
606 &[
607 0b10110000, 0b00000000, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0x10, 0, 0, 0, 1, 0, 0, 0, ][..],
619 mock_rx_info(&ap),
620 0.into(),
621 )
622 .await;
623
624 assert_eq!(ap.bss.as_mut().unwrap().clients.contains_key(&CLIENT_ADDR), true);
625
626 let msg = fake_device_state
627 .lock()
628 .next_mlme_msg::<fidl_mlme::AuthenticateIndication>()
629 .expect("expected MLME message");
630 assert_eq!(
631 msg,
632 fidl_mlme::AuthenticateIndication {
633 peer_sta_address: CLIENT_ADDR.to_array(),
634 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
635 },
636 );
637 }
638
639 #[fuchsia::test(allow_stalls = false)]
640 async fn ap_handle_mac_frame_ps_poll() {
641 let (mut ap, fake_device_state, _) = make_ap().await;
642 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
643 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
644
645 let client = ap.bss.as_mut().unwrap().clients.get_mut(&CLIENT_ADDR).unwrap();
646 client
647 .handle_mlme_auth_resp(&mut ap.ctx, fidl_mlme::AuthenticateResultCode::Success)
648 .await
649 .expect("expected OK");
650 client
651 .handle_mlme_assoc_resp(
652 &mut ap.ctx,
653 false,
654 fidl_ieee80211::ChannelNumber { number: 1, band: TwoGhz },
655 mac::CapabilityInfo(0),
656 fidl_mlme::AssociateResultCode::Success,
657 1,
658 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
659 )
660 .await
661 .expect("expected OK");
662 fake_device_state.lock().wlan_queue.clear();
663
664 ap.handle_mac_frame_rx(
666 &[
667 0b01001000, 0b00010001, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0x10, 0, ][..],
674 mock_rx_info(&ap),
675 0.into(),
676 )
677 .await;
678
679 ap.handle_eth_frame_tx(
680 &make_eth_frame(*CLIENT_ADDR, *CLIENT_ADDR2, 0x1234, &[1, 2, 3, 4, 5][..]),
681 0.into(),
682 );
683 assert_eq!(fake_device_state.lock().wlan_queue.len(), 0);
684
685 ap.handle_mac_frame_rx(
687 &[
688 0b10100100, 0b00000000, 0b00000001, 0b11000000, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, ][..],
694 mock_rx_info(&ap),
695 0.into(),
696 )
697 .await;
698
699 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
700 assert_eq!(
701 &fake_device_state.lock().wlan_queue[0].0[..],
702 &[
703 0b00001000, 0b00000010, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6, 0x30, 0, 0xAA, 0xAA, 0x03, 0, 0, 0, 0x12, 0x34, 1, 2, 3, 4, 5,
715 ][..]
716 );
717 }
718
719 #[fuchsia::test(allow_stalls = false)]
720 async fn ap_handle_mac_frame_no_such_client() {
721 let (mut ap, _, _) = make_ap().await;
722 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
723 ap.handle_mac_frame_rx(
724 &[
725 0b10100000, 0b00000001, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0x10, 0, 8, 0, ][..],
735 mock_rx_info(&ap),
736 0.into(),
737 )
738 .await;
739
740 assert_eq!(ap.bss.as_mut().unwrap().clients.contains_key(&CLIENT_ADDR), false);
741 }
742
743 #[fuchsia::test(allow_stalls = false)]
744 async fn ap_handle_mac_frame_bogus() {
745 let (mut ap, _, _) = make_ap().await;
746 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
747 ap.handle_mac_frame_rx(
748 &[0][..],
749 fidl_softmac::WlanRxInfo {
750 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
751 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
752 phy: fidl_ieee80211::WlanPhyType::Dsss,
753 data_rate: 0,
754 primary: fidl_ieee80211::ChannelNumber {
755 band: fidl_ieee80211::WlanBand::TwoGhz,
756 number: 0,
757 },
758 mcs: 0,
759 rssi_dbm: 0,
760 snr_dbh: 0,
761 bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
762 vht_secondary_80_channel: fidl_ieee80211::ChannelNumber {
763 band: fidl_ieee80211::WlanBand::TwoGhz,
764 number: 0,
765 },
766 },
767 0.into(),
768 )
769 .await;
770 }
771
772 #[fuchsia::test(allow_stalls = false)]
773 async fn ap_handle_mac_frame_wrong_channel_drop() {
774 let (mut ap, fake_device_state, _) = make_ap().await;
775 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
776 let probe_req = [
777 0b01000000, 0b00000000, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0x10, 0, 0, 7, 0x63, 0x6f, 0x6f, 0x6c, 0x6e, 0x65, 0x74, 0x0a,
786 ];
787 let rx_info_wrong_channel = fidl_softmac::WlanRxInfo {
788 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
789 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
790 phy: fidl_ieee80211::WlanPhyType::Dsss,
791 data_rate: 0,
792 primary: fidl_ieee80211::ChannelNumber {
793 band: fidl_ieee80211::WlanBand::TwoGhz,
794 number: 0,
795 },
796 mcs: 0,
797 rssi_dbm: 0,
798 snr_dbh: 0,
799 bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
800 vht_secondary_80_channel: fidl_ieee80211::ChannelNumber {
801 band: fidl_ieee80211::WlanBand::TwoGhz,
802 number: 0,
803 },
804 };
805 ap.handle_mac_frame_rx(&probe_req[..], rx_info_wrong_channel.clone(), 0.into()).await;
806
807 assert_eq!(fake_device_state.lock().wlan_queue.len(), 0);
809
810 let rx_info_same_channel = fidl_softmac::WlanRxInfo {
812 primary: fidl_ieee80211::ChannelNumber {
813 band: fidl_ieee80211::WlanBand::TwoGhz,
814 number: 1,
815 },
816 ..rx_info_wrong_channel
817 };
818 fake_device_state.lock().wlan_queue.clear();
819 ap.handle_mac_frame_rx(&probe_req[..], rx_info_same_channel, 0.into()).await;
820 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
821 }
822
823 #[fuchsia::test(allow_stalls = false)]
824 async fn ap_handle_mlme_start_req() {
825 let (mut ap, fake_device_state, _) = make_ap().await;
826 ap.handle_mlme_start_req(fidl_mlme::StartRequest {
827 ssid: Ssid::try_from("coolnet").unwrap().into(),
828 bss_type: fidl_ieee80211::BssType::Infrastructure,
829 beacon_period: 5,
830 dtim_period: 1,
831 primary: fidl_ieee80211::ChannelNumber {
832 band: fidl_ieee80211::WlanBand::TwoGhz,
833 number: 2,
834 },
835 bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
836 capability_info: CapabilityInfo(0).raw(),
837 rates: vec![0b11111000],
838 country: fidl_mlme::Country { alpha2: *b"xx", suffix: fidl_mlme::COUNTRY_ENVIRON_ALL },
839 mesh_id: vec![],
840 rsne: None,
841 phy: fidl_ieee80211::WlanPhyType::Erp,
842 })
843 .await
844 .expect("expected Ap::handle_mlme_start_request OK");
845
846 assert!(ap.bss.is_some());
847 {
848 let state = fake_device_state.lock();
849 assert_eq!(
850 state.wlan_channel,
851 fidl_ieee80211::ChannelNumber { band: fidl_ieee80211::WlanBand::TwoGhz, number: 2 }
852 );
853 assert_eq!(state.cbw, fidl_ieee80211::ChannelBandwidth::Cbw20);
854 assert_eq!(
855 state.secondary80,
856 fidl_ieee80211::ChannelNumber { band: fidl_ieee80211::WlanBand::TwoGhz, number: 0 }
857 );
858 }
859 assert_eq!(fake_device_state.lock().link_status, LinkStatus::UP);
860
861 let msg = fake_device_state
862 .lock()
863 .next_mlme_msg::<fidl_mlme::StartConfirm>()
864 .expect("expected MLME message");
865 assert_eq!(
866 msg,
867 fidl_mlme::StartConfirm { result_code: fidl_mlme::StartResultCode::Success },
868 );
869 }
870
871 #[fuchsia::test(allow_stalls = false)]
872 async fn ap_handle_mlme_start_req_already_started() {
873 let (mut ap, fake_device_state, _) = make_ap().await;
874 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
875
876 ap.handle_mlme_start_req(fidl_mlme::StartRequest {
877 ssid: Ssid::try_from("coolnet").unwrap().into(),
878 bss_type: fidl_ieee80211::BssType::Infrastructure,
879 beacon_period: 5,
880 dtim_period: 1,
881 primary: fidl_ieee80211::ChannelNumber {
882 band: fidl_ieee80211::WlanBand::TwoGhz,
883 number: 2,
884 },
885 bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
886 capability_info: CapabilityInfo(0).raw(),
887 rates: vec![],
888 country: fidl_mlme::Country { alpha2: *b"xx", suffix: fidl_mlme::COUNTRY_ENVIRON_ALL },
889 mesh_id: vec![],
890 rsne: None,
891 phy: fidl_ieee80211::WlanPhyType::Erp,
892 })
893 .await
894 .expect("expected Ap::handle_mlme_start_request OK");
895
896 let msg = fake_device_state
897 .lock()
898 .next_mlme_msg::<fidl_mlme::StartConfirm>()
899 .expect("expected MLME message");
900 assert_eq!(
901 msg,
902 fidl_mlme::StartConfirm {
903 result_code: fidl_mlme::StartResultCode::BssAlreadyStartedOrJoined
904 },
905 );
906 }
907
908 #[fuchsia::test(allow_stalls = false)]
909 async fn ap_handle_mlme_stop_req() {
910 let (mut ap, fake_device_state, _) = make_ap().await;
911 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
912
913 ap.handle_mlme_stop_req(fidl_mlme::StopRequest {
914 ssid: Ssid::try_from("coolnet").unwrap().into(),
915 })
916 .await
917 .expect("expected Ap::handle_mlme_stop_request OK");
918 assert!(ap.bss.is_none());
919 assert_eq!(fake_device_state.lock().link_status, LinkStatus::DOWN);
920
921 let msg = fake_device_state
922 .lock()
923 .next_mlme_msg::<fidl_mlme::StopConfirm>()
924 .expect("expected MLME message");
925 assert_eq!(msg, fidl_mlme::StopConfirm { result_code: fidl_mlme::StopResultCode::Success },);
926 }
927
928 #[fuchsia::test(allow_stalls = false)]
929 async fn ap_handle_mlme_stop_req_already_stopped() {
930 let (mut ap, fake_device_state, _) = make_ap().await;
931
932 ap.handle_mlme_stop_req(fidl_mlme::StopRequest {
933 ssid: Ssid::try_from("coolnet").unwrap().into(),
934 })
935 .await
936 .expect("expected Ap::handle_mlme_stop_request OK");
937 assert!(ap.bss.is_none());
938
939 let msg = fake_device_state
940 .lock()
941 .next_mlme_msg::<fidl_mlme::StopConfirm>()
942 .expect("expected MLME message");
943 assert_eq!(
944 msg,
945 fidl_mlme::StopConfirm { result_code: fidl_mlme::StopResultCode::BssAlreadyStopped },
946 );
947 }
948
949 #[fuchsia::test(allow_stalls = false)]
950 async fn ap_handle_mlme_setkeys_req() {
951 let (mut ap, fake_device_state, _) = make_ap().await;
952 ap.bss.replace(make_infra_bss(&mut ap.ctx, true).await);
953
954 ap.handle_mlme_setkeys_req(fidl_mlme::SetKeysRequest {
955 keylist: vec![fidl_mlme::SetKeyDescriptor {
956 cipher_suite_oui: [1, 2, 3],
957 cipher_suite_type: fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
958 key_type: fidl_mlme::KeyType::Pairwise,
959 address: [5; 6],
960 key_id: 6,
961 key: vec![1, 2, 3, 4, 5, 6, 7],
962 rsc: 8,
963 }],
964 })
965 .await
966 .expect("expected Ap::handle_mlme_setkeys_req OK");
967 assert_eq!(
968 fake_device_state.lock().keys,
969 vec![fidl_softmac::WlanKeyConfiguration {
970 protection: Some(fidl_softmac::WlanProtection::RxTx),
971 cipher_oui: Some([1, 2, 3]),
972 cipher_type: Some(4),
973 key_type: Some(fidl_ieee80211::KeyType::Pairwise),
974 peer_addr: Some([5; 6]),
975 key_idx: Some(6),
976 key: Some(vec![1, 2, 3, 4, 5, 6, 7]),
977 rsc: Some(8),
978 ..Default::default()
979 }]
980 );
981 }
982
983 #[fuchsia::test(allow_stalls = false)]
984 async fn ap_handle_mlme_setkeys_req_no_bss() {
985 let (mut ap, _, _) = make_ap().await;
986 assert_matches!(
987 ap.handle_mlme_setkeys_req(fidl_mlme::SetKeysRequest {
988 keylist: vec![fidl_mlme::SetKeyDescriptor {
989 cipher_suite_oui: [1, 2, 3],
990 cipher_suite_type:
991 fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
992 key_type: fidl_mlme::KeyType::Pairwise,
993 address: [5; 6],
994 key_id: 6,
995 key: vec![1, 2, 3, 4, 5, 6, 7],
996 rsc: 8,
997 }],
998 })
999 .await
1000 .expect_err("expected Ap::handle_mlme_setkeys_req error"),
1001 Error::Status(_, zx::Status::BAD_STATE)
1002 );
1003 }
1004
1005 #[fuchsia::test(allow_stalls = false)]
1006 async fn ap_handle_mlme_setkeys_req_bss_no_rsne() {
1007 let (mut ap, _, _) = make_ap().await;
1008 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
1009
1010 assert_matches!(
1011 ap.handle_mlme_setkeys_req(fidl_mlme::SetKeysRequest {
1012 keylist: vec![fidl_mlme::SetKeyDescriptor {
1013 cipher_suite_oui: [1, 2, 3],
1014 cipher_suite_type:
1015 fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
1016 key_type: fidl_mlme::KeyType::Pairwise,
1017 address: [5; 6],
1018 key_id: 6,
1019 key: vec![1, 2, 3, 4, 5, 6, 7],
1020 rsc: 8,
1021 }],
1022 })
1023 .await
1024 .expect_err("expected Ap::handle_mlme_setkeys_req error"),
1025 Error::Status(_, zx::Status::BAD_STATE)
1026 );
1027 }
1028
1029 #[fuchsia::test(allow_stalls = false)]
1030 async fn ap_handle_mlme_req_handle_mlme_auth_resp() {
1031 let (mut ap, fake_device_state, _) = make_ap().await;
1032 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
1033 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1034
1035 ap.handle_mlme_req(wlan_sme::MlmeRequest::AuthResponse(fidl_mlme::AuthenticateResponse {
1036 peer_sta_address: CLIENT_ADDR.to_array(),
1037 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
1038 }))
1039 .await
1040 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AuthenticateResp) ok");
1041 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1042 assert_eq!(
1043 &fake_device_state.lock().wlan_queue[0].0[..],
1044 &[
1045 0b10110000, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 0, 0, 2, 0, 76, 0, ][..]
1057 );
1058 }
1059
1060 #[fuchsia::test(allow_stalls = false)]
1061 async fn ap_handle_mlme_req_handle_mlme_auth_resp_no_bss() {
1062 let (mut ap, _, _) = make_ap().await;
1063
1064 assert_eq!(
1065 zx::Status::from(
1066 ap.handle_mlme_req(wlan_sme::MlmeRequest::AuthResponse(
1067 fidl_mlme::AuthenticateResponse {
1068 peer_sta_address: CLIENT_ADDR.to_array(),
1069 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
1070 }
1071 ))
1072 .await
1073 .expect_err(
1074 "expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AuthenticateResp) error"
1075 )
1076 ),
1077 zx::Status::BAD_STATE
1078 );
1079 }
1080
1081 #[fuchsia::test(allow_stalls = false)]
1082 async fn ap_handle_mlme_req_handle_mlme_auth_resp_no_such_client() {
1083 let (mut ap, _, _) = make_ap().await;
1084 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
1085
1086 assert_eq!(
1087 zx::Status::from(
1088 ap.handle_mlme_req(wlan_sme::MlmeRequest::AuthResponse(
1089 fidl_mlme::AuthenticateResponse {
1090 peer_sta_address: CLIENT_ADDR.to_array(),
1091 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
1092 }
1093 ))
1094 .await
1095 .expect_err(
1096 "expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AuthenticateResp) error"
1097 )
1098 ),
1099 zx::Status::NOT_FOUND
1100 );
1101 }
1102
1103 #[fuchsia::test(allow_stalls = false)]
1104 async fn ap_handle_mlme_req_handle_mlme_deauth_req() {
1105 let (mut ap, fake_device_state, _) = make_ap().await;
1106 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
1107 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1108
1109 ap.handle_mlme_req(wlan_sme::MlmeRequest::Deauthenticate(
1110 fidl_mlme::DeauthenticateRequest {
1111 peer_sta_address: CLIENT_ADDR.to_array(),
1112 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
1113 },
1114 ))
1115 .await
1116 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::DeauthenticateReq) ok");
1117 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1118 assert_eq!(
1119 &fake_device_state.lock().wlan_queue[0].0[..],
1120 &[
1121 0b11000000, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 3, 0, ][..]
1131 );
1132 }
1133
1134 #[fuchsia::test(allow_stalls = false)]
1135 async fn ap_handle_mlme_req_handle_mlme_assoc_resp() {
1136 let (mut ap, fake_device_state, _) = make_ap().await;
1137 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
1138 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1139
1140 ap.handle_mlme_req(wlan_sme::MlmeRequest::AssocResponse(fidl_mlme::AssociateResponse {
1141 peer_sta_address: CLIENT_ADDR.to_array(),
1142 result_code: fidl_mlme::AssociateResultCode::Success,
1143 association_id: 1,
1144 capability_info: CapabilityInfo(0).raw(),
1145 rates: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
1146 }))
1147 .await
1148 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AssociateResp) ok");
1149 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1150 assert_eq!(
1151 &fake_device_state.lock().wlan_queue[0].0[..],
1152 &[
1153 0b00010000, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 0, 0, 0, 0, 1, 0, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 2, 9, 10, 90, 3, 90, 0, 0, ][..]
1169 );
1170 }
1171
1172 #[fuchsia::test(allow_stalls = false)]
1173 async fn ap_handle_mlme_req_handle_mlme_disassoc_req() {
1174 let (mut ap, fake_device_state, _) = make_ap().await;
1175 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
1176 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1177
1178 ap.handle_mlme_req(wlan_sme::MlmeRequest::Disassociate(fidl_mlme::DisassociateRequest {
1179 peer_sta_address: CLIENT_ADDR.to_array(),
1180 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDisassoc,
1181 }))
1182 .await
1183 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::DisassociateReq) ok");
1184 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1185 assert_eq!(
1186 &fake_device_state.lock().wlan_queue[0].0[..],
1187 &[
1188 0b10100000, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 8, 0, ][..]
1198 );
1199 }
1200
1201 #[fuchsia::test(allow_stalls = false)]
1202 async fn ap_handle_mlme_req_handle_mlme_set_controlled_port_req() {
1203 let (mut ap, _, _) = make_ap().await;
1204 ap.bss.replace(make_infra_bss(&mut ap.ctx, true).await);
1205 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1206
1207 ap.handle_mlme_req(wlan_sme::MlmeRequest::AssocResponse(fidl_mlme::AssociateResponse {
1208 peer_sta_address: CLIENT_ADDR.to_array(),
1209 result_code: fidl_mlme::AssociateResultCode::Success,
1210 association_id: 1,
1211 capability_info: CapabilityInfo(0).raw(),
1212 rates: vec![1, 2, 3],
1213 }))
1214 .await
1215 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AssociateResp) ok");
1216
1217 ap.handle_mlme_req(wlan_sme::MlmeRequest::SetCtrlPort(
1218 fidl_mlme::SetControlledPortRequest {
1219 peer_sta_address: CLIENT_ADDR.to_array(),
1220 state: fidl_mlme::ControlledPortState::Open,
1221 },
1222 ))
1223 .await
1224 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::SetControlledPort) ok");
1225 }
1226
1227 #[fuchsia::test(allow_stalls = false)]
1228 async fn ap_handle_mlme_req_handle_mlme_eapol_req() {
1229 let (mut ap, fake_device_state, _) = make_ap().await;
1230 ap.bss.replace(make_infra_bss(&mut ap.ctx, false).await);
1231 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1232
1233 ap.handle_mlme_req(wlan_sme::MlmeRequest::Eapol(fidl_mlme::EapolRequest {
1234 dst_addr: CLIENT_ADDR.to_array(),
1235 src_addr: BSSID.to_array(),
1236 data: vec![1, 2, 3],
1237 }))
1238 .await
1239 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::EapolReq) ok");
1240 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1241 assert_eq!(
1242 &fake_device_state.lock().wlan_queue[0].0[..],
1243 &[
1244 0b00001000, 0b00000010, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 0xAA, 0xAA, 0x03, 0, 0, 0, 0x88, 0x8E, 1, 2, 3,
1256 ][..]
1257 );
1258 }
1259
1260 #[fuchsia::test(allow_stalls = false)]
1261 async fn ap_mlme_respond_to_query_device_info() {
1262 let (mut ap, _, _) = make_ap().await;
1263
1264 let (responder, receiver) = Responder::new();
1265 assert_matches!(
1266 ap.handle_mlme_req(wlan_sme::MlmeRequest::QueryDeviceInfo(responder)).await,
1267 Ok(())
1268 );
1269 assert_eq!(
1270 receiver.await.unwrap(),
1271 fidl_mlme::DeviceInfo {
1272 sta_addr: BSSID.to_array(),
1273 factory_addr: BSSID.to_array(),
1274 role: fidl_common::WlanMacRole::Ap,
1275 bands: test_utils::fake_mlme_band_caps(),
1276 softmac_hardware_capability: 0,
1277 qos_capable: false,
1278 }
1279 );
1280 }
1281
1282 #[fuchsia::test(allow_stalls = false)]
1283 async fn ap_mlme_respond_to_query_mac_sublayer_support() {
1284 let (mut ap, _, _) = make_ap().await;
1285
1286 let (responder, receiver) = Responder::new();
1287 assert_matches!(
1288 ap.handle_mlme_req(wlan_sme::MlmeRequest::QueryMacSublayerSupport(responder)).await,
1289 Ok(())
1290 );
1291 let resp = receiver.await.unwrap();
1292 assert_eq!(resp.rate_selection_offload.unwrap().supported, Some(false));
1293 assert_eq!(
1294 resp.data_plane.unwrap().data_plane_type,
1295 Some(fidl_common::DataPlaneType::EthernetDevice)
1296 );
1297 assert_eq!(resp.device.as_ref().unwrap().is_synthetic, Some(true));
1298 assert_eq!(
1299 resp.device.as_ref().unwrap().mac_implementation_type,
1300 Some(fidl_common::MacImplementationType::Softmac)
1301 );
1302 assert_eq!(resp.device.as_ref().unwrap().tx_status_report_supported, Some(true));
1303 }
1304
1305 #[fuchsia::test(allow_stalls = false)]
1306 async fn ap_mlme_respond_to_query_security_support() {
1307 let (mut ap, _, _) = make_ap().await;
1308
1309 let (responder, receiver) = Responder::new();
1310 assert_matches!(
1311 ap.handle_mlme_req(wlan_sme::MlmeRequest::QuerySecuritySupport(responder)).await,
1312 Ok(())
1313 );
1314 let resp = receiver.await.unwrap();
1315 assert_eq!(resp.mfp.unwrap().supported, Some(false));
1316 assert_eq!(resp.sae.as_ref().unwrap().driver_handler_supported, Some(false));
1317 assert_eq!(resp.sae.as_ref().unwrap().sme_handler_supported, Some(false));
1318 }
1319
1320 #[fuchsia::test(allow_stalls = false)]
1321 async fn ap_mlme_respond_to_query_spectrum_management_support() {
1322 let (mut ap, _, _) = make_ap().await;
1323
1324 let (responder, receiver) = Responder::new();
1325 assert_matches!(
1326 ap.handle_mlme_req(wlan_sme::MlmeRequest::QuerySpectrumManagementSupport(responder))
1327 .await,
1328 Ok(())
1329 );
1330 assert_eq!(receiver.await.unwrap().dfs.unwrap().supported, Some(true));
1331 }
1332
1333 #[test]
1334 fn display_rejection() {
1335 assert_eq!(format!("{}", Rejection::BadDsBits), "BadDsBits");
1336 }
1337}