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 ieee80211::{Bssid, MacAddr, Ssid};
15use log::{debug, error, info, trace, warn};
16use std::fmt;
17use wlan_common::TimeUnit;
18use wlan_common::mac::{self, CapabilityInfo};
19use wlan_common::timer::Timer;
20use zerocopy::SplitByteSlice;
21use {
22 fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_minstrel as fidl_minstrel,
23 fidl_fuchsia_wlan_mlme as fidl_mlme, fidl_fuchsia_wlan_softmac as fidl_softmac,
24 fuchsia_trace as trace, wlan_trace as wtrace,
25};
26
27use context::*;
28use infra_bss::*;
29use remote_client::*;
30
31#[derive(Debug)]
32struct BufferedFrame {
33 buffer: ArenaStaticBox<[u8]>,
34 tx_flags: fidl_softmac::WlanTxInfoFlags,
35 async_id: trace::Id,
36}
37
38#[derive(Debug)]
40pub enum Rejection {
41 OtherBss,
43
44 BadDsBits,
48
49 FrameMalformed,
53
54 NoSrcAddr,
56
57 NoSuchClient(MacAddr),
59
60 Client(MacAddr, ClientRejection),
62
63 Error(anyhow::Error),
65}
66
67impl Rejection {
68 fn log_level(&self) -> log::Level {
69 match self {
70 Self::NoSrcAddr | Self::FrameMalformed => log::Level::Error,
71 Self::Client(_, e) => e.log_level(),
72 _ => log::Level::Trace,
73 }
74 }
75 fn log(&self, msg: &str) {
76 match self.log_level() {
77 log::Level::Trace => trace!("{}: {}", msg, self),
78 log::Level::Debug => debug!("{}: {}", msg, self),
79 log::Level::Info => info!("{}: {}", msg, self),
80 log::Level::Warn => warn!("{}: {}", msg, self),
81 log::Level::Error => error!("{}: {}", msg, self),
82 }
83 }
84}
85
86impl fmt::Display for Rejection {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 match self {
89 Self::Client(addr, e) => write!(f, "client {:02X?}: {:?}", addr, e),
90 _ => fmt::Debug::fmt(self, f),
91 }
92 }
93}
94
95impl From<anyhow::Error> for Rejection {
96 fn from(e: anyhow::Error) -> Rejection {
97 Self::Error(e)
98 }
99}
100
101#[derive(Debug)]
102pub enum TimedEvent {
103 ClientEvent(MacAddr, ClientEvent),
105}
106
107pub struct Ap<D> {
108 ctx: Context<D>,
109 bss: Option<InfraBss>,
110}
111
112trait BssOptionExt<T: std::borrow::Borrow<InfraBss>> {
115 fn ok_or_bss_err(self) -> Result<T, Error>;
116}
117
118impl<T: std::borrow::Borrow<InfraBss>> BssOptionExt<T> for Option<T> {
119 fn ok_or_bss_err(self) -> Result<T, Error> {
120 self.ok_or(Error::Status(format!("BSS not started"), zx::Status::BAD_STATE))
121 }
122}
123
124impl<D: DeviceOps> crate::MlmeImpl for Ap<D> {
125 type Config = Bssid;
126 type Device = D;
127 type TimerEvent = TimedEvent;
128
129 async fn new(
130 config: Self::Config,
131 device: D,
132 timer: Timer<TimedEvent>,
133 ) -> Result<Self, anyhow::Error>
134 where
135 Self: Sized,
136 {
137 Ok(Self::new(device, timer, config))
138 }
139 async fn handle_mlme_request(
140 &mut self,
141 req: wlan_sme::MlmeRequest,
142 ) -> Result<(), anyhow::Error> {
143 Self::handle_mlme_req(self, req).await.map_err(|e| e.into())
144 }
145 async fn handle_mac_frame_rx(
146 &mut self,
147 frame: &[u8],
148 rx_info: fidl_softmac::WlanRxInfo,
149 async_id: trace::Id,
150 ) {
151 Self::handle_mac_frame_rx(self, frame, rx_info, async_id).await
152 }
153 fn handle_eth_frame_tx(
154 &mut self,
155 bytes: &[u8],
156 async_id: trace::Id,
157 ) -> Result<(), anyhow::Error> {
158 Self::handle_eth_frame_tx(self, bytes, async_id);
159 Ok(())
160 }
161 async fn handle_scan_complete(&mut self, _status: zx::Status, _scan_id: u64) {
162 warn!("Unexpected ScanComplete for AP MLME.");
163 return;
164 }
165 async fn handle_timeout(&mut self, event: TimedEvent) {
166 Self::handle_timed_event(self, event).await
167 }
168 fn access_device(&mut self) -> &mut Self::Device {
169 &mut self.ctx.device
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_common::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 self.bss.replace(
236 InfraBss::new(
237 &mut self.ctx,
238 Ssid::from_bytes_unchecked(req.ssid),
239 TimeUnit(req.beacon_period),
240 req.dtim_period,
241 CapabilityInfo(req.capability_info),
242 req.rates,
243 req.channel,
244 req.rsne,
245 )
246 .await?,
247 );
248
249 self.ctx.send_mlme_start_conf(fidl_mlme::StartResultCode::Success)?;
250
251 info!("MLME-START.request: OK");
252 Ok(())
253 }
254
255 async fn handle_mlme_stop_req(&mut self, _req: fidl_mlme::StopRequest) -> Result<(), Error> {
257 match self.bss.take() {
258 Some(bss) => match bss.stop(&mut self.ctx).await {
259 Ok(_) => self.ctx.send_mlme_stop_conf(fidl_mlme::StopResultCode::Success)?,
260 Err(e) => {
261 self.ctx.send_mlme_stop_conf(fidl_mlme::StopResultCode::InternalError)?;
262 return Err(e);
263 }
264 },
265 None => {
266 info!("MLME-STOP.request: BSS not started");
267 self.ctx.send_mlme_stop_conf(fidl_mlme::StopResultCode::BssAlreadyStopped)?;
268 }
269 }
270 info!("MLME-STOP.request: OK");
271 Ok(())
272 }
273
274 pub async fn handle_mlme_setkeys_req(
278 &mut self,
279 req: fidl_mlme::SetKeysRequest,
280 ) -> Result<(), Error> {
281 if let Some(bss) = self.bss.as_mut() {
282 bss.handle_mlme_setkeys_req(&mut self.ctx, req.keylist).await
283 } else {
284 Err(Error::Status(format!("cannot set keys on unstarted BSS"), zx::Status::BAD_STATE))
285 }
286 }
287
288 pub async fn handle_mlme_query_device_info(
289 &mut self,
290 responder: wlan_sme::responder::Responder<fidl_mlme::DeviceInfo>,
291 ) -> Result<(), Error> {
292 let info = ddk_converter::mlme_device_info_from_softmac(
293 device::try_query(&mut self.ctx.device).await?,
294 )?;
295 responder.respond(info);
296 Ok(())
297 }
298
299 pub async fn handle_mlme_query_mac_sublayer_support(
300 &mut self,
301 responder: wlan_sme::responder::Responder<fidl_common::MacSublayerSupport>,
302 ) -> Result<(), Error> {
303 let support = device::try_query_mac_sublayer_support(&mut self.ctx.device).await?;
304 responder.respond(support);
305 Ok(())
306 }
307
308 pub async fn handle_mlme_query_security_support(
309 &mut self,
310 responder: wlan_sme::responder::Responder<fidl_common::SecuritySupport>,
311 ) -> Result<(), Error> {
312 let support = device::try_query_security_support(&mut self.ctx.device).await?;
313 responder.respond(support);
314 Ok(())
315 }
316
317 pub async fn handle_mlme_query_spectrum_management_support(
318 &mut self,
319 responder: wlan_sme::responder::Responder<fidl_common::SpectrumManagementSupport>,
320 ) -> Result<(), Error> {
321 let support = device::try_query_spectrum_management_support(&mut self.ctx.device).await?;
322 responder.respond(support);
323 Ok(())
324 }
325
326 pub async fn handle_mlme_req(&mut self, req: wlan_sme::MlmeRequest) -> Result<(), Error> {
327 use wlan_sme::MlmeRequest as Req;
328 match req {
329 Req::Start(req) => self.handle_mlme_start_req(req).await,
330 Req::Stop(req) => self.handle_mlme_stop_req(req).await,
331 Req::SetKeys(req) => self.handle_mlme_setkeys_req(req).await,
332 Req::QueryDeviceInfo(responder) => self.handle_mlme_query_device_info(responder).await,
333 Req::QueryMacSublayerSupport(responder) => {
334 self.handle_mlme_query_mac_sublayer_support(responder).await
335 }
336 Req::QuerySecuritySupport(responder) => {
337 self.handle_mlme_query_security_support(responder).await
338 }
339 Req::QuerySpectrumManagementSupport(responder) => {
340 self.handle_mlme_query_spectrum_management_support(responder).await
341 }
342 Req::ListMinstrelPeers(responder) => self.handle_sme_list_minstrel_peers(responder),
343 Req::GetMinstrelStats(req, responder) => {
344 self.handle_sme_get_minstrel_stats(responder, &req.peer_addr.into())
345 }
346 Req::AuthResponse(resp) => {
347 info!("Handling MLME auth resp. self.bss.is_some()?: {}", self.bss.is_some());
349 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_auth_resp(&mut self.ctx, resp).await
350 }
351 Req::Deauthenticate(req) => {
352 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_deauth_req(&mut self.ctx, req).await
353 }
354 Req::AssocResponse(resp) => {
355 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_assoc_resp(&mut self.ctx, resp).await
356 }
357 Req::Disassociate(req) => {
358 self.bss
359 .as_mut()
360 .ok_or_bss_err()?
361 .handle_mlme_disassoc_req(&mut self.ctx, req)
362 .await
363 }
364 Req::SetCtrlPort(req) => {
365 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_set_controlled_port_req(req)
366 }
367 Req::Eapol(req) => {
368 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_eapol_req(&mut self.ctx, req)
369 }
370 _ => Err(Error::Status(format!("not supported"), zx::Status::NOT_SUPPORTED)),
371 }
372 .map_err(|e| {
373 error!("error handling MLME message: {}", e);
374 e
375 })
376 }
377
378 pub fn handle_eth_frame_tx(&mut self, frame: &[u8], async_id: trace::Id) {
379 let bss = match self.bss.as_mut() {
380 Some(bss) => bss,
381 None => {
382 error!("received Ethernet frame but BSS was not started yet");
383 return;
384 }
385 };
386
387 let mac::EthernetFrame { hdr, body } =
388 match mac::EthernetFrame::parse(frame).ok_or_else(|| Rejection::FrameMalformed) {
389 Ok(eth_frame) => eth_frame,
390 Err(e) => {
391 error!("failed to parse Ethernet frame: {}", e);
392 return;
393 }
394 };
395
396 if let Err(e) = bss.handle_eth_frame(&mut self.ctx, *hdr, body, async_id) {
397 e.log("failed to handle Ethernet frame")
398 }
399 }
400
401 pub async fn handle_mac_frame_rx<B: SplitByteSlice>(
402 &mut self,
403 bytes: B,
404 rx_info: fidl_softmac::WlanRxInfo,
405 async_id: trace::Id,
406 ) {
407 let bss = match self.bss.as_mut() {
408 Some(bss) => bss,
409 None => {
410 error!("received WLAN frame but BSS was not started yet");
411 wtrace::async_end_wlansoftmac_rx(async_id, "BSS not started");
412 return;
413 }
414 };
415
416 if rx_info.channel.primary != bss.channel {
418 wtrace::async_end_wlansoftmac_rx(async_id, "frame from wrong channel");
419 return;
420 }
421
422 let body_aligned = (rx_info.rx_flags & fidl_softmac::WlanRxInfoFlags::FRAME_BODY_PADDING_4)
423 != fidl_softmac::WlanRxInfoFlags::empty();
424
425 let mac_frame = match mac::MacFrame::parse(bytes, body_aligned) {
426 Some(mac_frame) => mac_frame,
427 None => {
428 error!("failed to parse MAC frame");
429 wtrace::async_end_wlansoftmac_rx(async_id, "failed to parse frame");
430 return;
431 }
432 };
433
434 if let Err(e) = match mac_frame {
435 mac::MacFrame::Mgmt(mgmt) => bss.handle_mgmt_frame(&mut self.ctx, mgmt).await,
436 mac::MacFrame::Data(data_frame) => bss.handle_data_frame(&mut self.ctx, data_frame),
437 mac::MacFrame::Ctrl(ctrl_frame) => bss.handle_ctrl_frame(&mut self.ctx, ctrl_frame),
438 mac::MacFrame::Unsupported { frame_ctrl } => {
439 error!("received unsupported MAC frame: frame_ctrl = {:?}", frame_ctrl);
440 wtrace::async_end_wlansoftmac_rx(async_id, "received unsupported frame");
441 return;
442 }
443 } {
444 wtrace::async_end_wlansoftmac_rx(async_id, "failed to handle frame");
445 e.log("failed to handle MAC frame")
446 } else {
447 wtrace::async_end_wlansoftmac_rx(async_id, "successfully handled frame");
448 }
449 }
450}
451
452#[cfg(test)]
453mod tests {
454 use super::*;
455 use crate::device::{FakeDevice, FakeDeviceConfig, FakeDeviceState, LinkStatus, test_utils};
456 use crate::test_utils::MockWlanRxInfo;
457 use assert_matches::assert_matches;
458 use fuchsia_sync::Mutex;
459 use ieee80211::MacAddrBytes;
460 use std::sync::{Arc, LazyLock};
461 use wlan_common::test_utils::fake_frames::fake_wpa2_rsne;
462 use wlan_common::timer;
463 use wlan_frame_writer::write_frame_to_vec;
464 use wlan_sme::responder::Responder;
465 use zerocopy::byteorder::big_endian::U16 as BigEndianU16;
466 use {
467 fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211,
468 fidl_fuchsia_wlan_softmac as fidl_softmac,
469 };
470
471 static CLIENT_ADDR: LazyLock<MacAddr> = LazyLock::new(|| [4u8; 6].into());
472 static BSSID: LazyLock<Bssid> = LazyLock::new(|| [2u8; 6].into());
473 static CLIENT_ADDR2: LazyLock<MacAddr> = LazyLock::new(|| [6u8; 6].into());
474
475 fn make_eth_frame(
476 dst_addr: MacAddr,
477 src_addr: MacAddr,
478 protocol_id: u16,
479 body: &[u8],
480 ) -> Vec<u8> {
481 write_frame_to_vec!({
482 headers: {
483 mac::EthernetIIHdr: &mac::EthernetIIHdr {
484 da: dst_addr,
485 sa: src_addr,
486 ether_type: BigEndianU16::new(protocol_id),
487 },
488 },
489 payload: body,
490 })
491 .unwrap() }
493
494 async fn make_ap()
498 -> (Ap<FakeDevice>, Arc<Mutex<FakeDeviceState>>, timer::EventStream<TimedEvent>) {
499 let (timer, time_stream) = timer::create_timer();
500 let (fake_device, fake_device_state) = FakeDevice::new_with_config(
501 FakeDeviceConfig::default()
502 .with_mock_mac_role(fidl_common::WlanMacRole::Ap)
503 .with_mock_sta_addr((*BSSID).to_array()),
504 )
505 .await;
506 (Ap::new(fake_device, timer, *BSSID), fake_device_state, time_stream)
507 }
508
509 #[fuchsia::test(allow_stalls = false)]
510 async fn ap_handle_eth_frame() {
511 let (mut ap, fake_device_state, _) = make_ap().await;
512 ap.bss.replace(
513 InfraBss::new(
514 &mut ap.ctx,
515 Ssid::try_from("coolnet").unwrap(),
516 TimeUnit::DEFAULT_BEACON_INTERVAL,
517 2,
518 CapabilityInfo(0),
519 vec![0b11111000],
520 1,
521 None,
522 )
523 .await
524 .expect("expected InfraBss::new ok"),
525 );
526 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
527
528 let client = ap.bss.as_mut().unwrap().clients.get_mut(&CLIENT_ADDR).unwrap();
529 client
530 .handle_mlme_auth_resp(&mut ap.ctx, fidl_mlme::AuthenticateResultCode::Success)
531 .await
532 .expect("expected OK");
533 client
534 .handle_mlme_assoc_resp(
535 &mut ap.ctx,
536 false,
537 1,
538 mac::CapabilityInfo(0),
539 fidl_mlme::AssociateResultCode::Success,
540 1,
541 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
542 )
543 .await
544 .expect("expected OK");
545 fake_device_state.lock().wlan_queue.clear();
546
547 ap.handle_eth_frame_tx(
548 &make_eth_frame(*CLIENT_ADDR, *CLIENT_ADDR2, 0x1234, &[1, 2, 3, 4, 5][..]),
549 0.into(),
550 );
551
552 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
553 assert_eq!(
554 &fake_device_state.lock().wlan_queue[0].0[..],
555 &[
556 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,
568 ][..]
569 );
570 }
571
572 #[fuchsia::test(allow_stalls = false)]
573 async fn ap_handle_eth_frame_no_such_client() {
574 let (mut ap, _, _) = make_ap().await;
575 ap.bss.replace(
576 InfraBss::new(
577 &mut ap.ctx,
578 Ssid::try_from("coolnet").unwrap(),
579 TimeUnit::DEFAULT_BEACON_INTERVAL,
580 2,
581 CapabilityInfo(0),
582 vec![0b11111000],
583 1,
584 None,
585 )
586 .await
587 .expect("expected InfraBss::new ok"),
588 );
589 ap.handle_eth_frame_tx(
590 &make_eth_frame(*CLIENT_ADDR2, *CLIENT_ADDR, 0x1234, &[1, 2, 3, 4, 5][..]),
591 0.into(),
592 );
593 }
594
595 fn mock_rx_info(ap: &Ap<FakeDevice>) -> fidl_softmac::WlanRxInfo {
596 let channel = fidl_ieee80211::WlanChannel {
597 primary: ap.bss.as_ref().unwrap().channel,
598 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
599 secondary80: 0,
600 };
601 MockWlanRxInfo::with_channel(channel).into()
602 }
603
604 #[fuchsia::test(allow_stalls = false)]
605 async fn ap_handle_mac_frame() {
606 let (mut ap, fake_device_state, _) = make_ap().await;
607 ap.bss.replace(
608 InfraBss::new(
609 &mut ap.ctx,
610 Ssid::try_from("coolnet").unwrap(),
611 TimeUnit::DEFAULT_BEACON_INTERVAL,
612 2,
613 CapabilityInfo(0),
614 vec![0b11111000],
615 1,
616 None,
617 )
618 .await
619 .expect("expected InfraBss::new ok"),
620 );
621 ap.handle_mac_frame_rx(
622 &[
623 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, ][..],
635 mock_rx_info(&ap),
636 0.into(),
637 )
638 .await;
639
640 assert_eq!(ap.bss.as_mut().unwrap().clients.contains_key(&CLIENT_ADDR), true);
641
642 let msg = fake_device_state
643 .lock()
644 .next_mlme_msg::<fidl_mlme::AuthenticateIndication>()
645 .expect("expected MLME message");
646 assert_eq!(
647 msg,
648 fidl_mlme::AuthenticateIndication {
649 peer_sta_address: CLIENT_ADDR.to_array(),
650 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
651 },
652 );
653 }
654
655 #[fuchsia::test(allow_stalls = false)]
656 async fn ap_handle_mac_frame_ps_poll() {
657 let (mut ap, fake_device_state, _) = make_ap().await;
658 ap.bss.replace(
659 InfraBss::new(
660 &mut ap.ctx,
661 Ssid::try_from("coolnet").unwrap(),
662 TimeUnit::DEFAULT_BEACON_INTERVAL,
663 2,
664 CapabilityInfo(0),
665 vec![0b11111000],
666 1,
667 None,
668 )
669 .await
670 .expect("expected InfraBss::new ok"),
671 );
672 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
673
674 let client = ap.bss.as_mut().unwrap().clients.get_mut(&CLIENT_ADDR).unwrap();
675 client
676 .handle_mlme_auth_resp(&mut ap.ctx, fidl_mlme::AuthenticateResultCode::Success)
677 .await
678 .expect("expected OK");
679 client
680 .handle_mlme_assoc_resp(
681 &mut ap.ctx,
682 false,
683 1,
684 mac::CapabilityInfo(0),
685 fidl_mlme::AssociateResultCode::Success,
686 1,
687 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
688 )
689 .await
690 .expect("expected OK");
691 fake_device_state.lock().wlan_queue.clear();
692
693 ap.handle_mac_frame_rx(
695 &[
696 0b01001000, 0b00010001, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0x10, 0, ][..],
703 mock_rx_info(&ap),
704 0.into(),
705 )
706 .await;
707
708 ap.handle_eth_frame_tx(
709 &make_eth_frame(*CLIENT_ADDR, *CLIENT_ADDR2, 0x1234, &[1, 2, 3, 4, 5][..]),
710 0.into(),
711 );
712 assert_eq!(fake_device_state.lock().wlan_queue.len(), 0);
713
714 ap.handle_mac_frame_rx(
716 &[
717 0b10100100, 0b00000000, 0b00000001, 0b11000000, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, ][..],
723 mock_rx_info(&ap),
724 0.into(),
725 )
726 .await;
727
728 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
729 assert_eq!(
730 &fake_device_state.lock().wlan_queue[0].0[..],
731 &[
732 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,
744 ][..]
745 );
746 }
747
748 #[fuchsia::test(allow_stalls = false)]
749 async fn ap_handle_mac_frame_no_such_client() {
750 let (mut ap, _, _) = make_ap().await;
751 ap.bss.replace(
752 InfraBss::new(
753 &mut ap.ctx,
754 Ssid::try_from("coolnet").unwrap(),
755 TimeUnit::DEFAULT_BEACON_INTERVAL,
756 2,
757 CapabilityInfo(0),
758 vec![0b11111000],
759 1,
760 None,
761 )
762 .await
763 .expect("expected InfraBss::new ok"),
764 );
765 ap.handle_mac_frame_rx(
766 &[
767 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, ][..],
777 mock_rx_info(&ap),
778 0.into(),
779 )
780 .await;
781
782 assert_eq!(ap.bss.as_mut().unwrap().clients.contains_key(&CLIENT_ADDR), false);
783 }
784
785 #[fuchsia::test(allow_stalls = false)]
786 async fn ap_handle_mac_frame_bogus() {
787 let (mut ap, _, _) = make_ap().await;
788 ap.bss.replace(
789 InfraBss::new(
790 &mut ap.ctx,
791 Ssid::try_from("coolnet").unwrap(),
792 TimeUnit::DEFAULT_BEACON_INTERVAL,
793 2,
794 CapabilityInfo(0),
795 vec![0b11111000],
796 1,
797 None,
798 )
799 .await
800 .expect("expected InfraBss::new ok"),
801 );
802 ap.handle_mac_frame_rx(
803 &[0][..],
804 fidl_softmac::WlanRxInfo {
805 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
806 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
807 phy: fidl_common::WlanPhyType::Dsss,
808 data_rate: 0,
809 channel: fidl_ieee80211::WlanChannel {
810 primary: 0,
811 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
812 secondary80: 0,
813 },
814 mcs: 0,
815 rssi_dbm: 0,
816 snr_dbh: 0,
817 },
818 0.into(),
819 )
820 .await;
821 }
822
823 #[fuchsia::test(allow_stalls = false)]
824 async fn ap_handle_mac_frame_wrong_channel_drop() {
825 let (mut ap, fake_device_state, _) = make_ap().await;
826 ap.bss.replace(
827 InfraBss::new(
828 &mut ap.ctx,
829 Ssid::try_from("coolnet").unwrap(),
830 TimeUnit::DEFAULT_BEACON_INTERVAL,
831 2,
832 CapabilityInfo(0),
833 vec![0b11111000],
834 1,
835 None,
836 )
837 .await
838 .expect("expected InfraBss::new ok"),
839 );
840 let probe_req = [
841 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,
850 ];
851 let rx_info_wrong_channel = fidl_softmac::WlanRxInfo {
852 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
853 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
854 phy: fidl_common::WlanPhyType::Dsss,
855 data_rate: 0,
856 channel: fidl_ieee80211::WlanChannel {
857 primary: 0,
858 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
859 secondary80: 0,
860 },
861 mcs: 0,
862 rssi_dbm: 0,
863 snr_dbh: 0,
864 };
865 ap.handle_mac_frame_rx(&probe_req[..], rx_info_wrong_channel.clone(), 0.into()).await;
866
867 assert_eq!(fake_device_state.lock().wlan_queue.len(), 0);
869
870 let rx_info_same_channel = fidl_softmac::WlanRxInfo {
872 channel: fidl_ieee80211::WlanChannel {
873 primary: 1,
874 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
875 secondary80: 0,
876 },
877 ..rx_info_wrong_channel
878 };
879 fake_device_state.lock().wlan_queue.clear();
880 ap.handle_mac_frame_rx(&probe_req[..], rx_info_same_channel, 0.into()).await;
881 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
882 }
883
884 #[fuchsia::test(allow_stalls = false)]
885 async fn ap_handle_mlme_start_req() {
886 let (mut ap, fake_device_state, _) = make_ap().await;
887 ap.handle_mlme_start_req(fidl_mlme::StartRequest {
888 ssid: Ssid::try_from("coolnet").unwrap().into(),
889 bss_type: fidl_common::BssType::Infrastructure,
890 beacon_period: 5,
891 dtim_period: 1,
892 channel: 2,
893 capability_info: CapabilityInfo(0).raw(),
894 rates: vec![0b11111000],
895 country: fidl_mlme::Country { alpha2: *b"xx", suffix: fidl_mlme::COUNTRY_ENVIRON_ALL },
896 mesh_id: vec![],
897 rsne: None,
898 phy: fidl_common::WlanPhyType::Erp,
899 channel_bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
900 })
901 .await
902 .expect("expected Ap::handle_mlme_start_request OK");
903
904 assert!(ap.bss.is_some());
905 assert_eq!(
906 fake_device_state.lock().wlan_channel,
907 fidl_ieee80211::WlanChannel {
908 primary: 2,
909 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
911 secondary80: 0,
912 }
913 );
914 assert_eq!(fake_device_state.lock().link_status, LinkStatus::UP);
915
916 let msg = fake_device_state
917 .lock()
918 .next_mlme_msg::<fidl_mlme::StartConfirm>()
919 .expect("expected MLME message");
920 assert_eq!(
921 msg,
922 fidl_mlme::StartConfirm { result_code: fidl_mlme::StartResultCode::Success },
923 );
924 }
925
926 #[fuchsia::test(allow_stalls = false)]
927 async fn ap_handle_mlme_start_req_already_started() {
928 let (mut ap, fake_device_state, _) = make_ap().await;
929 ap.bss.replace(
930 InfraBss::new(
931 &mut ap.ctx,
932 Ssid::try_from("coolnet").unwrap(),
933 TimeUnit::DEFAULT_BEACON_INTERVAL,
934 2,
935 CapabilityInfo(0),
936 vec![0b11111000],
937 1,
938 None,
939 )
940 .await
941 .expect("expected InfraBss::new ok"),
942 );
943
944 ap.handle_mlme_start_req(fidl_mlme::StartRequest {
945 ssid: Ssid::try_from("coolnet").unwrap().into(),
946 bss_type: fidl_common::BssType::Infrastructure,
947 beacon_period: 5,
948 dtim_period: 1,
949 channel: 2,
950 capability_info: CapabilityInfo(0).raw(),
951 rates: vec![],
952 country: fidl_mlme::Country { alpha2: *b"xx", suffix: fidl_mlme::COUNTRY_ENVIRON_ALL },
953 mesh_id: vec![],
954 rsne: None,
955 phy: fidl_common::WlanPhyType::Erp,
956 channel_bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw20,
957 })
958 .await
959 .expect("expected Ap::handle_mlme_start_request OK");
960
961 let msg = fake_device_state
962 .lock()
963 .next_mlme_msg::<fidl_mlme::StartConfirm>()
964 .expect("expected MLME message");
965 assert_eq!(
966 msg,
967 fidl_mlme::StartConfirm {
968 result_code: fidl_mlme::StartResultCode::BssAlreadyStartedOrJoined
969 },
970 );
971 }
972
973 #[fuchsia::test(allow_stalls = false)]
974 async fn ap_handle_mlme_stop_req() {
975 let (mut ap, fake_device_state, _) = make_ap().await;
976 ap.bss.replace(
977 InfraBss::new(
978 &mut ap.ctx,
979 Ssid::try_from("coolnet").unwrap(),
980 TimeUnit::DEFAULT_BEACON_INTERVAL,
981 2,
982 CapabilityInfo(0),
983 vec![0b11111000],
984 1,
985 None,
986 )
987 .await
988 .expect("expected InfraBss::new ok"),
989 );
990
991 ap.handle_mlme_stop_req(fidl_mlme::StopRequest {
992 ssid: Ssid::try_from("coolnet").unwrap().into(),
993 })
994 .await
995 .expect("expected Ap::handle_mlme_stop_request OK");
996 assert!(ap.bss.is_none());
997 assert_eq!(fake_device_state.lock().link_status, LinkStatus::DOWN);
998
999 let msg = fake_device_state
1000 .lock()
1001 .next_mlme_msg::<fidl_mlme::StopConfirm>()
1002 .expect("expected MLME message");
1003 assert_eq!(msg, fidl_mlme::StopConfirm { result_code: fidl_mlme::StopResultCode::Success },);
1004 }
1005
1006 #[fuchsia::test(allow_stalls = false)]
1007 async fn ap_handle_mlme_stop_req_already_stopped() {
1008 let (mut ap, fake_device_state, _) = make_ap().await;
1009
1010 ap.handle_mlme_stop_req(fidl_mlme::StopRequest {
1011 ssid: Ssid::try_from("coolnet").unwrap().into(),
1012 })
1013 .await
1014 .expect("expected Ap::handle_mlme_stop_request OK");
1015 assert!(ap.bss.is_none());
1016
1017 let msg = fake_device_state
1018 .lock()
1019 .next_mlme_msg::<fidl_mlme::StopConfirm>()
1020 .expect("expected MLME message");
1021 assert_eq!(
1022 msg,
1023 fidl_mlme::StopConfirm { result_code: fidl_mlme::StopResultCode::BssAlreadyStopped },
1024 );
1025 }
1026
1027 #[fuchsia::test(allow_stalls = false)]
1028 async fn ap_handle_mlme_setkeys_req() {
1029 let (mut ap, fake_device_state, _) = make_ap().await;
1030 ap.bss.replace(
1031 InfraBss::new(
1032 &mut ap.ctx,
1033 Ssid::try_from("coolnet").unwrap(),
1034 TimeUnit::DEFAULT_BEACON_INTERVAL,
1035 2,
1036 CapabilityInfo(0),
1037 vec![0b11111000],
1038 1,
1039 Some(fake_wpa2_rsne()),
1040 )
1041 .await
1042 .expect("expected InfraBss::new ok"),
1043 );
1044
1045 ap.handle_mlme_setkeys_req(fidl_mlme::SetKeysRequest {
1046 keylist: vec![fidl_mlme::SetKeyDescriptor {
1047 cipher_suite_oui: [1, 2, 3],
1048 cipher_suite_type: fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
1049 key_type: fidl_mlme::KeyType::Pairwise,
1050 address: [5; 6],
1051 key_id: 6,
1052 key: vec![1, 2, 3, 4, 5, 6, 7],
1053 rsc: 8,
1054 }],
1055 })
1056 .await
1057 .expect("expected Ap::handle_mlme_setkeys_req OK");
1058 assert_eq!(
1059 fake_device_state.lock().keys,
1060 vec![fidl_softmac::WlanKeyConfiguration {
1061 protection: Some(fidl_softmac::WlanProtection::RxTx),
1062 cipher_oui: Some([1, 2, 3]),
1063 cipher_type: Some(4),
1064 key_type: Some(fidl_ieee80211::KeyType::Pairwise),
1065 peer_addr: Some([5; 6]),
1066 key_idx: Some(6),
1067 key: Some(vec![1, 2, 3, 4, 5, 6, 7]),
1068 rsc: Some(8),
1069 ..Default::default()
1070 }]
1071 );
1072 }
1073
1074 #[fuchsia::test(allow_stalls = false)]
1075 async fn ap_handle_mlme_setkeys_req_no_bss() {
1076 let (mut ap, _, _) = make_ap().await;
1077 assert_matches!(
1078 ap.handle_mlme_setkeys_req(fidl_mlme::SetKeysRequest {
1079 keylist: vec![fidl_mlme::SetKeyDescriptor {
1080 cipher_suite_oui: [1, 2, 3],
1081 cipher_suite_type:
1082 fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
1083 key_type: fidl_mlme::KeyType::Pairwise,
1084 address: [5; 6],
1085 key_id: 6,
1086 key: vec![1, 2, 3, 4, 5, 6, 7],
1087 rsc: 8,
1088 }],
1089 })
1090 .await
1091 .expect_err("expected Ap::handle_mlme_setkeys_req error"),
1092 Error::Status(_, zx::Status::BAD_STATE)
1093 );
1094 }
1095
1096 #[fuchsia::test(allow_stalls = false)]
1097 async fn ap_handle_mlme_setkeys_req_bss_no_rsne() {
1098 let (mut ap, _, _) = make_ap().await;
1099 ap.bss.replace(
1100 InfraBss::new(
1101 &mut ap.ctx,
1102 Ssid::try_from("coolnet").unwrap(),
1103 TimeUnit::DEFAULT_BEACON_INTERVAL,
1104 2,
1105 CapabilityInfo(0),
1106 vec![0b11111000],
1107 1,
1108 None,
1109 )
1110 .await
1111 .expect("expected InfraBss::new ok"),
1112 );
1113
1114 assert_matches!(
1115 ap.handle_mlme_setkeys_req(fidl_mlme::SetKeysRequest {
1116 keylist: vec![fidl_mlme::SetKeyDescriptor {
1117 cipher_suite_oui: [1, 2, 3],
1118 cipher_suite_type:
1119 fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
1120 key_type: fidl_mlme::KeyType::Pairwise,
1121 address: [5; 6],
1122 key_id: 6,
1123 key: vec![1, 2, 3, 4, 5, 6, 7],
1124 rsc: 8,
1125 }],
1126 })
1127 .await
1128 .expect_err("expected Ap::handle_mlme_setkeys_req error"),
1129 Error::Status(_, zx::Status::BAD_STATE)
1130 );
1131 }
1132
1133 #[fuchsia::test(allow_stalls = false)]
1134 async fn ap_handle_mlme_req_handle_mlme_auth_resp() {
1135 let (mut ap, fake_device_state, _) = make_ap().await;
1136 ap.bss.replace(
1137 InfraBss::new(
1138 &mut ap.ctx,
1139 Ssid::try_from("coolnet").unwrap(),
1140 TimeUnit::DEFAULT_BEACON_INTERVAL,
1141 2,
1142 CapabilityInfo(0),
1143 vec![0b11111000],
1144 1,
1145 None,
1146 )
1147 .await
1148 .expect("expected InfraBss::new ok"),
1149 );
1150 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1151
1152 ap.handle_mlme_req(wlan_sme::MlmeRequest::AuthResponse(fidl_mlme::AuthenticateResponse {
1153 peer_sta_address: CLIENT_ADDR.to_array(),
1154 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
1155 }))
1156 .await
1157 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AuthenticateResp) ok");
1158 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1159 assert_eq!(
1160 &fake_device_state.lock().wlan_queue[0].0[..],
1161 &[
1162 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, ][..]
1174 );
1175 }
1176
1177 #[fuchsia::test(allow_stalls = false)]
1178 async fn ap_handle_mlme_req_handle_mlme_auth_resp_no_bss() {
1179 let (mut ap, _, _) = make_ap().await;
1180
1181 assert_eq!(
1182 zx::Status::from(
1183 ap.handle_mlme_req(wlan_sme::MlmeRequest::AuthResponse(
1184 fidl_mlme::AuthenticateResponse {
1185 peer_sta_address: CLIENT_ADDR.to_array(),
1186 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
1187 }
1188 ))
1189 .await
1190 .expect_err(
1191 "expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AuthenticateResp) error"
1192 )
1193 ),
1194 zx::Status::BAD_STATE
1195 );
1196 }
1197
1198 #[fuchsia::test(allow_stalls = false)]
1199 async fn ap_handle_mlme_req_handle_mlme_auth_resp_no_such_client() {
1200 let (mut ap, _, _) = make_ap().await;
1201 ap.bss.replace(
1202 InfraBss::new(
1203 &mut ap.ctx,
1204 Ssid::try_from("coolnet").unwrap(),
1205 TimeUnit::DEFAULT_BEACON_INTERVAL,
1206 2,
1207 CapabilityInfo(0),
1208 vec![0b11111000],
1209 1,
1210 None,
1211 )
1212 .await
1213 .expect("expected InfraBss::new ok"),
1214 );
1215
1216 assert_eq!(
1217 zx::Status::from(
1218 ap.handle_mlme_req(wlan_sme::MlmeRequest::AuthResponse(
1219 fidl_mlme::AuthenticateResponse {
1220 peer_sta_address: CLIENT_ADDR.to_array(),
1221 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
1222 }
1223 ))
1224 .await
1225 .expect_err(
1226 "expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AuthenticateResp) error"
1227 )
1228 ),
1229 zx::Status::NOT_FOUND
1230 );
1231 }
1232
1233 #[fuchsia::test(allow_stalls = false)]
1234 async fn ap_handle_mlme_req_handle_mlme_deauth_req() {
1235 let (mut ap, fake_device_state, _) = make_ap().await;
1236 ap.bss.replace(
1237 InfraBss::new(
1238 &mut ap.ctx,
1239 Ssid::try_from("coolnet").unwrap(),
1240 TimeUnit::DEFAULT_BEACON_INTERVAL,
1241 2,
1242 CapabilityInfo(0),
1243 vec![0b11111000],
1244 1,
1245 None,
1246 )
1247 .await
1248 .expect("expected InfraBss::new ok"),
1249 );
1250 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1251
1252 ap.handle_mlme_req(wlan_sme::MlmeRequest::Deauthenticate(
1253 fidl_mlme::DeauthenticateRequest {
1254 peer_sta_address: CLIENT_ADDR.to_array(),
1255 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
1256 },
1257 ))
1258 .await
1259 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::DeauthenticateReq) ok");
1260 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1261 assert_eq!(
1262 &fake_device_state.lock().wlan_queue[0].0[..],
1263 &[
1264 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, ][..]
1274 );
1275 }
1276
1277 #[fuchsia::test(allow_stalls = false)]
1278 async fn ap_handle_mlme_req_handle_mlme_assoc_resp() {
1279 let (mut ap, fake_device_state, _) = make_ap().await;
1280 ap.bss.replace(
1281 InfraBss::new(
1282 &mut ap.ctx,
1283 Ssid::try_from("coolnet").unwrap(),
1284 TimeUnit::DEFAULT_BEACON_INTERVAL,
1285 2,
1286 CapabilityInfo(0),
1287 vec![0b11111000],
1288 1,
1289 None,
1290 )
1291 .await
1292 .expect("expected InfraBss::new ok"),
1293 );
1294 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1295
1296 ap.handle_mlme_req(wlan_sme::MlmeRequest::AssocResponse(fidl_mlme::AssociateResponse {
1297 peer_sta_address: CLIENT_ADDR.to_array(),
1298 result_code: fidl_mlme::AssociateResultCode::Success,
1299 association_id: 1,
1300 capability_info: CapabilityInfo(0).raw(),
1301 rates: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
1302 }))
1303 .await
1304 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AssociateResp) ok");
1305 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1306 assert_eq!(
1307 &fake_device_state.lock().wlan_queue[0].0[..],
1308 &[
1309 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, ][..]
1325 );
1326 }
1327
1328 #[fuchsia::test(allow_stalls = false)]
1329 async fn ap_handle_mlme_req_handle_mlme_disassoc_req() {
1330 let (mut ap, fake_device_state, _) = make_ap().await;
1331 ap.bss.replace(
1332 InfraBss::new(
1333 &mut ap.ctx,
1334 Ssid::try_from("coolnet").unwrap(),
1335 TimeUnit::DEFAULT_BEACON_INTERVAL,
1336 2,
1337 CapabilityInfo(0),
1338 vec![0b11111000],
1339 1,
1340 None,
1341 )
1342 .await
1343 .expect("expected InfraBss::new ok"),
1344 );
1345 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1346
1347 ap.handle_mlme_req(wlan_sme::MlmeRequest::Disassociate(fidl_mlme::DisassociateRequest {
1348 peer_sta_address: CLIENT_ADDR.to_array(),
1349 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDisassoc,
1350 }))
1351 .await
1352 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::DisassociateReq) ok");
1353 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1354 assert_eq!(
1355 &fake_device_state.lock().wlan_queue[0].0[..],
1356 &[
1357 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, ][..]
1367 );
1368 }
1369
1370 #[fuchsia::test(allow_stalls = false)]
1371 async fn ap_handle_mlme_req_handle_mlme_set_controlled_port_req() {
1372 let (mut ap, _, _) = make_ap().await;
1373 ap.bss.replace(
1374 InfraBss::new(
1375 &mut ap.ctx,
1376 Ssid::try_from("coolnet").unwrap(),
1377 TimeUnit::DEFAULT_BEACON_INTERVAL,
1378 2,
1379 CapabilityInfo(0),
1380 vec![0b11111000],
1381 1,
1382 Some(fake_wpa2_rsne()),
1383 )
1384 .await
1385 .expect("expected InfraBss::new ok"),
1386 );
1387 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1388
1389 ap.handle_mlme_req(wlan_sme::MlmeRequest::AssocResponse(fidl_mlme::AssociateResponse {
1390 peer_sta_address: CLIENT_ADDR.to_array(),
1391 result_code: fidl_mlme::AssociateResultCode::Success,
1392 association_id: 1,
1393 capability_info: CapabilityInfo(0).raw(),
1394 rates: vec![1, 2, 3],
1395 }))
1396 .await
1397 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AssociateResp) ok");
1398
1399 ap.handle_mlme_req(wlan_sme::MlmeRequest::SetCtrlPort(
1400 fidl_mlme::SetControlledPortRequest {
1401 peer_sta_address: CLIENT_ADDR.to_array(),
1402 state: fidl_mlme::ControlledPortState::Open,
1403 },
1404 ))
1405 .await
1406 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::SetControlledPort) ok");
1407 }
1408
1409 #[fuchsia::test(allow_stalls = false)]
1410 async fn ap_handle_mlme_req_handle_mlme_eapol_req() {
1411 let (mut ap, fake_device_state, _) = make_ap().await;
1412 ap.bss.replace(
1413 InfraBss::new(
1414 &mut ap.ctx,
1415 Ssid::try_from("coolnet").unwrap(),
1416 TimeUnit::DEFAULT_BEACON_INTERVAL,
1417 2,
1418 CapabilityInfo(0),
1419 vec![0b11111000],
1420 1,
1421 None,
1422 )
1423 .await
1424 .expect("expected InfraBss::new ok"),
1425 );
1426 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1427
1428 ap.handle_mlme_req(wlan_sme::MlmeRequest::Eapol(fidl_mlme::EapolRequest {
1429 dst_addr: CLIENT_ADDR.to_array(),
1430 src_addr: BSSID.to_array(),
1431 data: vec![1, 2, 3],
1432 }))
1433 .await
1434 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::EapolReq) ok");
1435 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1436 assert_eq!(
1437 &fake_device_state.lock().wlan_queue[0].0[..],
1438 &[
1439 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,
1451 ][..]
1452 );
1453 }
1454
1455 #[fuchsia::test(allow_stalls = false)]
1456 async fn ap_mlme_respond_to_query_device_info() {
1457 let (mut ap, _, _) = make_ap().await;
1458
1459 let (responder, receiver) = Responder::new();
1460 assert_matches!(
1461 ap.handle_mlme_req(wlan_sme::MlmeRequest::QueryDeviceInfo(responder)).await,
1462 Ok(())
1463 );
1464 assert_eq!(
1465 receiver.await.unwrap(),
1466 fidl_mlme::DeviceInfo {
1467 sta_addr: BSSID.to_array(),
1468 role: fidl_common::WlanMacRole::Ap,
1469 bands: test_utils::fake_mlme_band_caps(),
1470 softmac_hardware_capability: 0,
1471 qos_capable: false,
1472 }
1473 );
1474 }
1475
1476 #[fuchsia::test(allow_stalls = false)]
1477 async fn ap_mlme_respond_to_query_mac_sublayer_support() {
1478 let (mut ap, _, _) = make_ap().await;
1479
1480 let (responder, receiver) = Responder::new();
1481 assert_matches!(
1482 ap.handle_mlme_req(wlan_sme::MlmeRequest::QueryMacSublayerSupport(responder)).await,
1483 Ok(())
1484 );
1485 let resp = receiver.await.unwrap();
1486 assert_eq!(resp.rate_selection_offload.supported, false);
1487 assert_eq!(resp.data_plane.data_plane_type, fidl_common::DataPlaneType::EthernetDevice);
1488 assert_eq!(resp.device.is_synthetic, true);
1489 assert_eq!(
1490 resp.device.mac_implementation_type,
1491 fidl_common::MacImplementationType::Softmac
1492 );
1493 assert_eq!(resp.device.tx_status_report_supported, true);
1494 }
1495
1496 #[fuchsia::test(allow_stalls = false)]
1497 async fn ap_mlme_respond_to_query_security_support() {
1498 let (mut ap, _, _) = make_ap().await;
1499
1500 let (responder, receiver) = Responder::new();
1501 assert_matches!(
1502 ap.handle_mlme_req(wlan_sme::MlmeRequest::QuerySecuritySupport(responder)).await,
1503 Ok(())
1504 );
1505 let resp = receiver.await.unwrap();
1506 assert_eq!(resp.mfp.supported, false);
1507 assert_eq!(resp.sae.driver_handler_supported, false);
1508 assert_eq!(resp.sae.sme_handler_supported, false);
1509 }
1510
1511 #[fuchsia::test(allow_stalls = false)]
1512 async fn ap_mlme_respond_to_query_spectrum_management_support() {
1513 let (mut ap, _, _) = make_ap().await;
1514
1515 let (responder, receiver) = Responder::new();
1516 assert_matches!(
1517 ap.handle_mlme_req(wlan_sme::MlmeRequest::QuerySpectrumManagementSupport(responder))
1518 .await,
1519 Ok(())
1520 );
1521 assert_eq!(receiver.await.unwrap().dfs.supported, true);
1522 }
1523
1524 #[test]
1525 fn display_rejection() {
1526 assert_eq!(format!("{}", Rejection::BadDsBits), "BadDsBits");
1527 }
1528}