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::mac::{self, CapabilityInfo};
18use wlan_common::timer::Timer;
19use wlan_common::TimeUnit;
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_discovery_support(
300 &mut self,
301 responder: wlan_sme::responder::Responder<fidl_common::DiscoverySupport>,
302 ) -> Result<(), Error> {
303 let support = device::try_query_discovery_support(&mut self.ctx.device).await?;
304 responder.respond(support);
305 Ok(())
306 }
307
308 pub async fn handle_mlme_query_mac_sublayer_support(
309 &mut self,
310 responder: wlan_sme::responder::Responder<fidl_common::MacSublayerSupport>,
311 ) -> Result<(), Error> {
312 let support = device::try_query_mac_sublayer_support(&mut self.ctx.device).await?;
313 responder.respond(support);
314 Ok(())
315 }
316
317 pub async fn handle_mlme_query_security_support(
318 &mut self,
319 responder: wlan_sme::responder::Responder<fidl_common::SecuritySupport>,
320 ) -> Result<(), Error> {
321 let support = device::try_query_security_support(&mut self.ctx.device).await?;
322 responder.respond(support);
323 Ok(())
324 }
325
326 pub async fn handle_mlme_query_spectrum_management_support(
327 &mut self,
328 responder: wlan_sme::responder::Responder<fidl_common::SpectrumManagementSupport>,
329 ) -> Result<(), Error> {
330 let support = device::try_query_spectrum_management_support(&mut self.ctx.device).await?;
331 responder.respond(support);
332 Ok(())
333 }
334
335 pub async fn handle_mlme_req(&mut self, req: wlan_sme::MlmeRequest) -> Result<(), Error> {
336 use wlan_sme::MlmeRequest as Req;
337 match req {
338 Req::Start(req) => self.handle_mlme_start_req(req).await,
339 Req::Stop(req) => self.handle_mlme_stop_req(req).await,
340 Req::SetKeys(req) => self.handle_mlme_setkeys_req(req).await,
341 Req::QueryDeviceInfo(responder) => self.handle_mlme_query_device_info(responder).await,
342 Req::QueryDiscoverySupport(responder) => {
343 self.handle_mlme_query_discovery_support(responder).await
344 }
345 Req::QueryMacSublayerSupport(responder) => {
346 self.handle_mlme_query_mac_sublayer_support(responder).await
347 }
348 Req::QuerySecuritySupport(responder) => {
349 self.handle_mlme_query_security_support(responder).await
350 }
351 Req::QuerySpectrumManagementSupport(responder) => {
352 self.handle_mlme_query_spectrum_management_support(responder).await
353 }
354 Req::ListMinstrelPeers(responder) => self.handle_sme_list_minstrel_peers(responder),
355 Req::GetMinstrelStats(req, responder) => {
356 self.handle_sme_get_minstrel_stats(responder, &req.peer_addr.into())
357 }
358 Req::AuthResponse(resp) => {
359 info!("Handling MLME auth resp. self.bss.is_some()?: {}", self.bss.is_some());
361 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_auth_resp(&mut self.ctx, resp).await
362 }
363 Req::Deauthenticate(req) => {
364 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_deauth_req(&mut self.ctx, req).await
365 }
366 Req::AssocResponse(resp) => {
367 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_assoc_resp(&mut self.ctx, resp).await
368 }
369 Req::Disassociate(req) => {
370 self.bss
371 .as_mut()
372 .ok_or_bss_err()?
373 .handle_mlme_disassoc_req(&mut self.ctx, req)
374 .await
375 }
376 Req::SetCtrlPort(req) => {
377 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_set_controlled_port_req(req)
378 }
379 Req::Eapol(req) => {
380 self.bss.as_mut().ok_or_bss_err()?.handle_mlme_eapol_req(&mut self.ctx, req)
381 }
382 _ => Err(Error::Status(format!("not supported"), zx::Status::NOT_SUPPORTED)),
383 }
384 .map_err(|e| {
385 error!("error handling MLME message: {}", e);
386 e
387 })
388 }
389
390 pub fn handle_eth_frame_tx(&mut self, frame: &[u8], async_id: trace::Id) {
391 let bss = match self.bss.as_mut() {
392 Some(bss) => bss,
393 None => {
394 error!("received Ethernet frame but BSS was not started yet");
395 return;
396 }
397 };
398
399 let mac::EthernetFrame { hdr, body } =
400 match mac::EthernetFrame::parse(frame).ok_or_else(|| Rejection::FrameMalformed) {
401 Ok(eth_frame) => eth_frame,
402 Err(e) => {
403 error!("failed to parse Ethernet frame: {}", e);
404 return;
405 }
406 };
407
408 if let Err(e) = bss.handle_eth_frame(&mut self.ctx, *hdr, body, async_id) {
409 e.log("failed to handle Ethernet frame")
410 }
411 }
412
413 pub async fn handle_mac_frame_rx<B: SplitByteSlice>(
414 &mut self,
415 bytes: B,
416 rx_info: fidl_softmac::WlanRxInfo,
417 async_id: trace::Id,
418 ) {
419 let bss = match self.bss.as_mut() {
420 Some(bss) => bss,
421 None => {
422 error!("received WLAN frame but BSS was not started yet");
423 wtrace::async_end_wlansoftmac_rx(async_id, "BSS not started");
424 return;
425 }
426 };
427
428 if rx_info.channel.primary != bss.channel {
430 wtrace::async_end_wlansoftmac_rx(async_id, "frame from wrong channel");
431 return;
432 }
433
434 let body_aligned = (rx_info.rx_flags & fidl_softmac::WlanRxInfoFlags::FRAME_BODY_PADDING_4)
435 != fidl_softmac::WlanRxInfoFlags::empty();
436
437 let mac_frame = match mac::MacFrame::parse(bytes, body_aligned) {
438 Some(mac_frame) => mac_frame,
439 None => {
440 error!("failed to parse MAC frame");
441 wtrace::async_end_wlansoftmac_rx(async_id, "failed to parse frame");
442 return;
443 }
444 };
445
446 if let Err(e) = match mac_frame {
447 mac::MacFrame::Mgmt(mgmt) => bss.handle_mgmt_frame(&mut self.ctx, mgmt).await,
448 mac::MacFrame::Data(data_frame) => bss.handle_data_frame(&mut self.ctx, data_frame),
449 mac::MacFrame::Ctrl(ctrl_frame) => bss.handle_ctrl_frame(&mut self.ctx, ctrl_frame),
450 mac::MacFrame::Unsupported { frame_ctrl } => {
451 error!("received unsupported MAC frame: frame_ctrl = {:?}", frame_ctrl);
452 wtrace::async_end_wlansoftmac_rx(async_id, "received unsupported frame");
453 return;
454 }
455 } {
456 wtrace::async_end_wlansoftmac_rx(async_id, "failed to handle frame");
457 e.log("failed to handle MAC frame")
458 } else {
459 wtrace::async_end_wlansoftmac_rx(async_id, "successfully handled frame");
460 }
461 }
462}
463
464#[cfg(test)]
465mod tests {
466 use super::*;
467 use crate::device::{test_utils, FakeDevice, FakeDeviceConfig, FakeDeviceState, LinkStatus};
468 use crate::test_utils::MockWlanRxInfo;
469 use fuchsia_sync::Mutex;
470 use ieee80211::MacAddrBytes;
471 use lazy_static::lazy_static;
472 use std::sync::Arc;
473 use wlan_common::big_endian::BigEndianU16;
474 use wlan_common::test_utils::fake_frames::fake_wpa2_rsne;
475 use wlan_common::{assert_variant, timer};
476 use wlan_frame_writer::write_frame_to_vec;
477 use wlan_sme::responder::Responder;
478 use {
479 fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211,
480 fidl_fuchsia_wlan_softmac as fidl_softmac,
481 };
482
483 lazy_static! {
484 static ref CLIENT_ADDR: MacAddr = [4u8; 6].into();
485 static ref BSSID: Bssid = [2u8; 6].into();
486 static ref CLIENT_ADDR2: MacAddr = [6u8; 6].into();
487 }
488
489 fn make_eth_frame(
490 dst_addr: MacAddr,
491 src_addr: MacAddr,
492 protocol_id: u16,
493 body: &[u8],
494 ) -> Vec<u8> {
495 write_frame_to_vec!({
496 headers: {
497 mac::EthernetIIHdr: &mac::EthernetIIHdr {
498 da: dst_addr,
499 sa: src_addr,
500 ether_type: BigEndianU16::from_native(protocol_id),
501 },
502 },
503 payload: body,
504 })
505 .unwrap() }
507
508 async fn make_ap(
512 ) -> (Ap<FakeDevice>, Arc<Mutex<FakeDeviceState>>, timer::EventStream<TimedEvent>) {
513 let (timer, time_stream) = timer::create_timer();
514 let (fake_device, fake_device_state) = FakeDevice::new_with_config(
515 FakeDeviceConfig::default()
516 .with_mock_mac_role(fidl_common::WlanMacRole::Ap)
517 .with_mock_sta_addr((*BSSID).to_array()),
518 )
519 .await;
520 (Ap::new(fake_device, timer, *BSSID), fake_device_state, time_stream)
521 }
522
523 #[fuchsia::test(allow_stalls = false)]
524 async fn ap_handle_eth_frame() {
525 let (mut ap, fake_device_state, _) = make_ap().await;
526 ap.bss.replace(
527 InfraBss::new(
528 &mut ap.ctx,
529 Ssid::try_from("coolnet").unwrap(),
530 TimeUnit::DEFAULT_BEACON_INTERVAL,
531 2,
532 CapabilityInfo(0),
533 vec![0b11111000],
534 1,
535 None,
536 )
537 .await
538 .expect("expected InfraBss::new ok"),
539 );
540 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
541
542 let client = ap.bss.as_mut().unwrap().clients.get_mut(&CLIENT_ADDR).unwrap();
543 client
544 .handle_mlme_auth_resp(&mut ap.ctx, fidl_mlme::AuthenticateResultCode::Success)
545 .await
546 .expect("expected OK");
547 client
548 .handle_mlme_assoc_resp(
549 &mut ap.ctx,
550 false,
551 1,
552 mac::CapabilityInfo(0),
553 fidl_mlme::AssociateResultCode::Success,
554 1,
555 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
556 )
557 .await
558 .expect("expected OK");
559 fake_device_state.lock().wlan_queue.clear();
560
561 ap.handle_eth_frame_tx(
562 &make_eth_frame(*CLIENT_ADDR, *CLIENT_ADDR2, 0x1234, &[1, 2, 3, 4, 5][..]),
563 0.into(),
564 );
565
566 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
567 assert_eq!(
568 &fake_device_state.lock().wlan_queue[0].0[..],
569 &[
570 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,
582 ][..]
583 );
584 }
585
586 #[fuchsia::test(allow_stalls = false)]
587 async fn ap_handle_eth_frame_no_such_client() {
588 let (mut ap, _, _) = make_ap().await;
589 ap.bss.replace(
590 InfraBss::new(
591 &mut ap.ctx,
592 Ssid::try_from("coolnet").unwrap(),
593 TimeUnit::DEFAULT_BEACON_INTERVAL,
594 2,
595 CapabilityInfo(0),
596 vec![0b11111000],
597 1,
598 None,
599 )
600 .await
601 .expect("expected InfraBss::new ok"),
602 );
603 ap.handle_eth_frame_tx(
604 &make_eth_frame(*CLIENT_ADDR2, *CLIENT_ADDR, 0x1234, &[1, 2, 3, 4, 5][..]),
605 0.into(),
606 );
607 }
608
609 fn mock_rx_info(ap: &Ap<FakeDevice>) -> fidl_softmac::WlanRxInfo {
610 let channel = fidl_common::WlanChannel {
611 primary: ap.bss.as_ref().unwrap().channel,
612 cbw: fidl_common::ChannelBandwidth::Cbw20,
613 secondary80: 0,
614 };
615 MockWlanRxInfo::with_channel(channel).into()
616 }
617
618 #[fuchsia::test(allow_stalls = false)]
619 async fn ap_handle_mac_frame() {
620 let (mut ap, fake_device_state, _) = make_ap().await;
621 ap.bss.replace(
622 InfraBss::new(
623 &mut ap.ctx,
624 Ssid::try_from("coolnet").unwrap(),
625 TimeUnit::DEFAULT_BEACON_INTERVAL,
626 2,
627 CapabilityInfo(0),
628 vec![0b11111000],
629 1,
630 None,
631 )
632 .await
633 .expect("expected InfraBss::new ok"),
634 );
635 ap.handle_mac_frame_rx(
636 &[
637 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, ][..],
649 mock_rx_info(&ap),
650 0.into(),
651 )
652 .await;
653
654 assert_eq!(ap.bss.as_mut().unwrap().clients.contains_key(&CLIENT_ADDR), true);
655
656 let msg = fake_device_state
657 .lock()
658 .next_mlme_msg::<fidl_mlme::AuthenticateIndication>()
659 .expect("expected MLME message");
660 assert_eq!(
661 msg,
662 fidl_mlme::AuthenticateIndication {
663 peer_sta_address: CLIENT_ADDR.to_array(),
664 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
665 },
666 );
667 }
668
669 #[fuchsia::test(allow_stalls = false)]
670 async fn ap_handle_mac_frame_ps_poll() {
671 let (mut ap, fake_device_state, _) = make_ap().await;
672 ap.bss.replace(
673 InfraBss::new(
674 &mut ap.ctx,
675 Ssid::try_from("coolnet").unwrap(),
676 TimeUnit::DEFAULT_BEACON_INTERVAL,
677 2,
678 CapabilityInfo(0),
679 vec![0b11111000],
680 1,
681 None,
682 )
683 .await
684 .expect("expected InfraBss::new ok"),
685 );
686 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
687
688 let client = ap.bss.as_mut().unwrap().clients.get_mut(&CLIENT_ADDR).unwrap();
689 client
690 .handle_mlme_auth_resp(&mut ap.ctx, fidl_mlme::AuthenticateResultCode::Success)
691 .await
692 .expect("expected OK");
693 client
694 .handle_mlme_assoc_resp(
695 &mut ap.ctx,
696 false,
697 1,
698 mac::CapabilityInfo(0),
699 fidl_mlme::AssociateResultCode::Success,
700 1,
701 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
702 )
703 .await
704 .expect("expected OK");
705 fake_device_state.lock().wlan_queue.clear();
706
707 ap.handle_mac_frame_rx(
709 &[
710 0b01001000, 0b00010001, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0x10, 0, ][..],
717 mock_rx_info(&ap),
718 0.into(),
719 )
720 .await;
721
722 ap.handle_eth_frame_tx(
723 &make_eth_frame(*CLIENT_ADDR, *CLIENT_ADDR2, 0x1234, &[1, 2, 3, 4, 5][..]),
724 0.into(),
725 );
726 assert_eq!(fake_device_state.lock().wlan_queue.len(), 0);
727
728 ap.handle_mac_frame_rx(
730 &[
731 0b10100100, 0b00000000, 0b00000001, 0b11000000, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, ][..],
737 mock_rx_info(&ap),
738 0.into(),
739 )
740 .await;
741
742 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
743 assert_eq!(
744 &fake_device_state.lock().wlan_queue[0].0[..],
745 &[
746 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,
758 ][..]
759 );
760 }
761
762 #[fuchsia::test(allow_stalls = false)]
763 async fn ap_handle_mac_frame_no_such_client() {
764 let (mut ap, _, _) = make_ap().await;
765 ap.bss.replace(
766 InfraBss::new(
767 &mut ap.ctx,
768 Ssid::try_from("coolnet").unwrap(),
769 TimeUnit::DEFAULT_BEACON_INTERVAL,
770 2,
771 CapabilityInfo(0),
772 vec![0b11111000],
773 1,
774 None,
775 )
776 .await
777 .expect("expected InfraBss::new ok"),
778 );
779 ap.handle_mac_frame_rx(
780 &[
781 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, ][..],
791 mock_rx_info(&ap),
792 0.into(),
793 )
794 .await;
795
796 assert_eq!(ap.bss.as_mut().unwrap().clients.contains_key(&CLIENT_ADDR), false);
797 }
798
799 #[fuchsia::test(allow_stalls = false)]
800 async fn ap_handle_mac_frame_bogus() {
801 let (mut ap, _, _) = make_ap().await;
802 ap.bss.replace(
803 InfraBss::new(
804 &mut ap.ctx,
805 Ssid::try_from("coolnet").unwrap(),
806 TimeUnit::DEFAULT_BEACON_INTERVAL,
807 2,
808 CapabilityInfo(0),
809 vec![0b11111000],
810 1,
811 None,
812 )
813 .await
814 .expect("expected InfraBss::new ok"),
815 );
816 ap.handle_mac_frame_rx(
817 &[0][..],
818 fidl_softmac::WlanRxInfo {
819 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
820 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
821 phy: fidl_common::WlanPhyType::Dsss,
822 data_rate: 0,
823 channel: fidl_common::WlanChannel {
824 primary: 0,
825 cbw: fidl_common::ChannelBandwidth::Cbw20,
826 secondary80: 0,
827 },
828 mcs: 0,
829 rssi_dbm: 0,
830 snr_dbh: 0,
831 },
832 0.into(),
833 )
834 .await;
835 }
836
837 #[fuchsia::test(allow_stalls = false)]
838 async fn ap_handle_mac_frame_wrong_channel_drop() {
839 let (mut ap, fake_device_state, _) = make_ap().await;
840 ap.bss.replace(
841 InfraBss::new(
842 &mut ap.ctx,
843 Ssid::try_from("coolnet").unwrap(),
844 TimeUnit::DEFAULT_BEACON_INTERVAL,
845 2,
846 CapabilityInfo(0),
847 vec![0b11111000],
848 1,
849 None,
850 )
851 .await
852 .expect("expected InfraBss::new ok"),
853 );
854 let probe_req = [
855 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,
864 ];
865 let rx_info_wrong_channel = fidl_softmac::WlanRxInfo {
866 rx_flags: fidl_softmac::WlanRxInfoFlags::empty(),
867 valid_fields: fidl_softmac::WlanRxInfoValid::empty(),
868 phy: fidl_common::WlanPhyType::Dsss,
869 data_rate: 0,
870 channel: fidl_common::WlanChannel {
871 primary: 0,
872 cbw: fidl_common::ChannelBandwidth::Cbw20,
873 secondary80: 0,
874 },
875 mcs: 0,
876 rssi_dbm: 0,
877 snr_dbh: 0,
878 };
879 ap.handle_mac_frame_rx(&probe_req[..], rx_info_wrong_channel.clone(), 0.into()).await;
880
881 assert_eq!(fake_device_state.lock().wlan_queue.len(), 0);
883
884 let rx_info_same_channel = fidl_softmac::WlanRxInfo {
886 channel: fidl_common::WlanChannel {
887 primary: 1,
888 cbw: fidl_common::ChannelBandwidth::Cbw20,
889 secondary80: 0,
890 },
891 ..rx_info_wrong_channel
892 };
893 fake_device_state.lock().wlan_queue.clear();
894 ap.handle_mac_frame_rx(&probe_req[..], rx_info_same_channel, 0.into()).await;
895 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
896 }
897
898 #[fuchsia::test(allow_stalls = false)]
899 async fn ap_handle_mlme_start_req() {
900 let (mut ap, fake_device_state, _) = make_ap().await;
901 ap.handle_mlme_start_req(fidl_mlme::StartRequest {
902 ssid: Ssid::try_from("coolnet").unwrap().into(),
903 bss_type: fidl_common::BssType::Infrastructure,
904 beacon_period: 5,
905 dtim_period: 1,
906 channel: 2,
907 capability_info: CapabilityInfo(0).raw(),
908 rates: vec![0b11111000],
909 country: fidl_mlme::Country { alpha2: *b"xx", suffix: fidl_mlme::COUNTRY_ENVIRON_ALL },
910 mesh_id: vec![],
911 rsne: None,
912 phy: fidl_common::WlanPhyType::Erp,
913 channel_bandwidth: fidl_common::ChannelBandwidth::Cbw20,
914 })
915 .await
916 .expect("expected Ap::handle_mlme_start_request OK");
917
918 assert!(ap.bss.is_some());
919 assert_eq!(
920 fake_device_state.lock().wlan_channel,
921 fidl_common::WlanChannel {
922 primary: 2,
923 cbw: fidl_common::ChannelBandwidth::Cbw20,
925 secondary80: 0,
926 }
927 );
928 assert_eq!(fake_device_state.lock().link_status, LinkStatus::UP);
929
930 let msg = fake_device_state
931 .lock()
932 .next_mlme_msg::<fidl_mlme::StartConfirm>()
933 .expect("expected MLME message");
934 assert_eq!(
935 msg,
936 fidl_mlme::StartConfirm { result_code: fidl_mlme::StartResultCode::Success },
937 );
938 }
939
940 #[fuchsia::test(allow_stalls = false)]
941 async fn ap_handle_mlme_start_req_already_started() {
942 let (mut ap, fake_device_state, _) = make_ap().await;
943 ap.bss.replace(
944 InfraBss::new(
945 &mut ap.ctx,
946 Ssid::try_from("coolnet").unwrap(),
947 TimeUnit::DEFAULT_BEACON_INTERVAL,
948 2,
949 CapabilityInfo(0),
950 vec![0b11111000],
951 1,
952 None,
953 )
954 .await
955 .expect("expected InfraBss::new ok"),
956 );
957
958 ap.handle_mlme_start_req(fidl_mlme::StartRequest {
959 ssid: Ssid::try_from("coolnet").unwrap().into(),
960 bss_type: fidl_common::BssType::Infrastructure,
961 beacon_period: 5,
962 dtim_period: 1,
963 channel: 2,
964 capability_info: CapabilityInfo(0).raw(),
965 rates: vec![],
966 country: fidl_mlme::Country { alpha2: *b"xx", suffix: fidl_mlme::COUNTRY_ENVIRON_ALL },
967 mesh_id: vec![],
968 rsne: None,
969 phy: fidl_common::WlanPhyType::Erp,
970 channel_bandwidth: fidl_common::ChannelBandwidth::Cbw20,
971 })
972 .await
973 .expect("expected Ap::handle_mlme_start_request OK");
974
975 let msg = fake_device_state
976 .lock()
977 .next_mlme_msg::<fidl_mlme::StartConfirm>()
978 .expect("expected MLME message");
979 assert_eq!(
980 msg,
981 fidl_mlme::StartConfirm {
982 result_code: fidl_mlme::StartResultCode::BssAlreadyStartedOrJoined
983 },
984 );
985 }
986
987 #[fuchsia::test(allow_stalls = false)]
988 async fn ap_handle_mlme_stop_req() {
989 let (mut ap, fake_device_state, _) = make_ap().await;
990 ap.bss.replace(
991 InfraBss::new(
992 &mut ap.ctx,
993 Ssid::try_from("coolnet").unwrap(),
994 TimeUnit::DEFAULT_BEACON_INTERVAL,
995 2,
996 CapabilityInfo(0),
997 vec![0b11111000],
998 1,
999 None,
1000 )
1001 .await
1002 .expect("expected InfraBss::new ok"),
1003 );
1004
1005 ap.handle_mlme_stop_req(fidl_mlme::StopRequest {
1006 ssid: Ssid::try_from("coolnet").unwrap().into(),
1007 })
1008 .await
1009 .expect("expected Ap::handle_mlme_stop_request OK");
1010 assert!(ap.bss.is_none());
1011 assert_eq!(fake_device_state.lock().link_status, LinkStatus::DOWN);
1012
1013 let msg = fake_device_state
1014 .lock()
1015 .next_mlme_msg::<fidl_mlme::StopConfirm>()
1016 .expect("expected MLME message");
1017 assert_eq!(msg, fidl_mlme::StopConfirm { result_code: fidl_mlme::StopResultCode::Success },);
1018 }
1019
1020 #[fuchsia::test(allow_stalls = false)]
1021 async fn ap_handle_mlme_stop_req_already_stopped() {
1022 let (mut ap, fake_device_state, _) = make_ap().await;
1023
1024 ap.handle_mlme_stop_req(fidl_mlme::StopRequest {
1025 ssid: Ssid::try_from("coolnet").unwrap().into(),
1026 })
1027 .await
1028 .expect("expected Ap::handle_mlme_stop_request OK");
1029 assert!(ap.bss.is_none());
1030
1031 let msg = fake_device_state
1032 .lock()
1033 .next_mlme_msg::<fidl_mlme::StopConfirm>()
1034 .expect("expected MLME message");
1035 assert_eq!(
1036 msg,
1037 fidl_mlme::StopConfirm { result_code: fidl_mlme::StopResultCode::BssAlreadyStopped },
1038 );
1039 }
1040
1041 #[fuchsia::test(allow_stalls = false)]
1042 async fn ap_handle_mlme_setkeys_req() {
1043 let (mut ap, fake_device_state, _) = make_ap().await;
1044 ap.bss.replace(
1045 InfraBss::new(
1046 &mut ap.ctx,
1047 Ssid::try_from("coolnet").unwrap(),
1048 TimeUnit::DEFAULT_BEACON_INTERVAL,
1049 2,
1050 CapabilityInfo(0),
1051 vec![0b11111000],
1052 1,
1053 Some(fake_wpa2_rsne()),
1054 )
1055 .await
1056 .expect("expected InfraBss::new ok"),
1057 );
1058
1059 ap.handle_mlme_setkeys_req(fidl_mlme::SetKeysRequest {
1060 keylist: vec![fidl_mlme::SetKeyDescriptor {
1061 cipher_suite_oui: [1, 2, 3],
1062 cipher_suite_type: fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
1063 key_type: fidl_mlme::KeyType::Pairwise,
1064 address: [5; 6],
1065 key_id: 6,
1066 key: vec![1, 2, 3, 4, 5, 6, 7],
1067 rsc: 8,
1068 }],
1069 })
1070 .await
1071 .expect("expected Ap::handle_mlme_setkeys_req OK");
1072 assert_eq!(
1073 fake_device_state.lock().keys,
1074 vec![fidl_softmac::WlanKeyConfiguration {
1075 protection: Some(fidl_softmac::WlanProtection::RxTx),
1076 cipher_oui: Some([1, 2, 3]),
1077 cipher_type: Some(4),
1078 key_type: Some(fidl_ieee80211::KeyType::Pairwise),
1079 peer_addr: Some([5; 6]),
1080 key_idx: Some(6),
1081 key: Some(vec![1, 2, 3, 4, 5, 6, 7]),
1082 rsc: Some(8),
1083 ..Default::default()
1084 }]
1085 );
1086 }
1087
1088 #[fuchsia::test(allow_stalls = false)]
1089 async fn ap_handle_mlme_setkeys_req_no_bss() {
1090 let (mut ap, _, _) = make_ap().await;
1091 assert_variant!(
1092 ap.handle_mlme_setkeys_req(fidl_mlme::SetKeysRequest {
1093 keylist: vec![fidl_mlme::SetKeyDescriptor {
1094 cipher_suite_oui: [1, 2, 3],
1095 cipher_suite_type:
1096 fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
1097 key_type: fidl_mlme::KeyType::Pairwise,
1098 address: [5; 6],
1099 key_id: 6,
1100 key: vec![1, 2, 3, 4, 5, 6, 7],
1101 rsc: 8,
1102 }],
1103 })
1104 .await
1105 .expect_err("expected Ap::handle_mlme_setkeys_req error"),
1106 Error::Status(_, zx::Status::BAD_STATE)
1107 );
1108 }
1109
1110 #[fuchsia::test(allow_stalls = false)]
1111 async fn ap_handle_mlme_setkeys_req_bss_no_rsne() {
1112 let (mut ap, _, _) = make_ap().await;
1113 ap.bss.replace(
1114 InfraBss::new(
1115 &mut ap.ctx,
1116 Ssid::try_from("coolnet").unwrap(),
1117 TimeUnit::DEFAULT_BEACON_INTERVAL,
1118 2,
1119 CapabilityInfo(0),
1120 vec![0b11111000],
1121 1,
1122 None,
1123 )
1124 .await
1125 .expect("expected InfraBss::new ok"),
1126 );
1127
1128 assert_variant!(
1129 ap.handle_mlme_setkeys_req(fidl_mlme::SetKeysRequest {
1130 keylist: vec![fidl_mlme::SetKeyDescriptor {
1131 cipher_suite_oui: [1, 2, 3],
1132 cipher_suite_type:
1133 fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
1134 key_type: fidl_mlme::KeyType::Pairwise,
1135 address: [5; 6],
1136 key_id: 6,
1137 key: vec![1, 2, 3, 4, 5, 6, 7],
1138 rsc: 8,
1139 }],
1140 })
1141 .await
1142 .expect_err("expected Ap::handle_mlme_setkeys_req error"),
1143 Error::Status(_, zx::Status::BAD_STATE)
1144 );
1145 }
1146
1147 #[fuchsia::test(allow_stalls = false)]
1148 async fn ap_handle_mlme_req_handle_mlme_auth_resp() {
1149 let (mut ap, fake_device_state, _) = make_ap().await;
1150 ap.bss.replace(
1151 InfraBss::new(
1152 &mut ap.ctx,
1153 Ssid::try_from("coolnet").unwrap(),
1154 TimeUnit::DEFAULT_BEACON_INTERVAL,
1155 2,
1156 CapabilityInfo(0),
1157 vec![0b11111000],
1158 1,
1159 None,
1160 )
1161 .await
1162 .expect("expected InfraBss::new ok"),
1163 );
1164 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1165
1166 ap.handle_mlme_req(wlan_sme::MlmeRequest::AuthResponse(fidl_mlme::AuthenticateResponse {
1167 peer_sta_address: CLIENT_ADDR.to_array(),
1168 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
1169 }))
1170 .await
1171 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AuthenticateResp) ok");
1172 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1173 assert_eq!(
1174 &fake_device_state.lock().wlan_queue[0].0[..],
1175 &[
1176 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, ][..]
1188 );
1189 }
1190
1191 #[fuchsia::test(allow_stalls = false)]
1192 async fn ap_handle_mlme_req_handle_mlme_auth_resp_no_bss() {
1193 let (mut ap, _, _) = make_ap().await;
1194
1195 assert_eq!(
1196 zx::Status::from(
1197 ap.handle_mlme_req(wlan_sme::MlmeRequest::AuthResponse(
1198 fidl_mlme::AuthenticateResponse {
1199 peer_sta_address: CLIENT_ADDR.to_array(),
1200 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
1201 }
1202 ))
1203 .await
1204 .expect_err(
1205 "expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AuthenticateResp) error"
1206 )
1207 ),
1208 zx::Status::BAD_STATE
1209 );
1210 }
1211
1212 #[fuchsia::test(allow_stalls = false)]
1213 async fn ap_handle_mlme_req_handle_mlme_auth_resp_no_such_client() {
1214 let (mut ap, _, _) = make_ap().await;
1215 ap.bss.replace(
1216 InfraBss::new(
1217 &mut ap.ctx,
1218 Ssid::try_from("coolnet").unwrap(),
1219 TimeUnit::DEFAULT_BEACON_INTERVAL,
1220 2,
1221 CapabilityInfo(0),
1222 vec![0b11111000],
1223 1,
1224 None,
1225 )
1226 .await
1227 .expect("expected InfraBss::new ok"),
1228 );
1229
1230 assert_eq!(
1231 zx::Status::from(
1232 ap.handle_mlme_req(wlan_sme::MlmeRequest::AuthResponse(
1233 fidl_mlme::AuthenticateResponse {
1234 peer_sta_address: CLIENT_ADDR.to_array(),
1235 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
1236 }
1237 ))
1238 .await
1239 .expect_err(
1240 "expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AuthenticateResp) error"
1241 )
1242 ),
1243 zx::Status::NOT_FOUND
1244 );
1245 }
1246
1247 #[fuchsia::test(allow_stalls = false)]
1248 async fn ap_handle_mlme_req_handle_mlme_deauth_req() {
1249 let (mut ap, fake_device_state, _) = make_ap().await;
1250 ap.bss.replace(
1251 InfraBss::new(
1252 &mut ap.ctx,
1253 Ssid::try_from("coolnet").unwrap(),
1254 TimeUnit::DEFAULT_BEACON_INTERVAL,
1255 2,
1256 CapabilityInfo(0),
1257 vec![0b11111000],
1258 1,
1259 None,
1260 )
1261 .await
1262 .expect("expected InfraBss::new ok"),
1263 );
1264 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1265
1266 ap.handle_mlme_req(wlan_sme::MlmeRequest::Deauthenticate(
1267 fidl_mlme::DeauthenticateRequest {
1268 peer_sta_address: CLIENT_ADDR.to_array(),
1269 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
1270 },
1271 ))
1272 .await
1273 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::DeauthenticateReq) ok");
1274 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1275 assert_eq!(
1276 &fake_device_state.lock().wlan_queue[0].0[..],
1277 &[
1278 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, ][..]
1288 );
1289 }
1290
1291 #[fuchsia::test(allow_stalls = false)]
1292 async fn ap_handle_mlme_req_handle_mlme_assoc_resp() {
1293 let (mut ap, fake_device_state, _) = make_ap().await;
1294 ap.bss.replace(
1295 InfraBss::new(
1296 &mut ap.ctx,
1297 Ssid::try_from("coolnet").unwrap(),
1298 TimeUnit::DEFAULT_BEACON_INTERVAL,
1299 2,
1300 CapabilityInfo(0),
1301 vec![0b11111000],
1302 1,
1303 None,
1304 )
1305 .await
1306 .expect("expected InfraBss::new ok"),
1307 );
1308 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1309
1310 ap.handle_mlme_req(wlan_sme::MlmeRequest::AssocResponse(fidl_mlme::AssociateResponse {
1311 peer_sta_address: CLIENT_ADDR.to_array(),
1312 result_code: fidl_mlme::AssociateResultCode::Success,
1313 association_id: 1,
1314 capability_info: CapabilityInfo(0).raw(),
1315 rates: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
1316 }))
1317 .await
1318 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AssociateResp) ok");
1319 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1320 assert_eq!(
1321 &fake_device_state.lock().wlan_queue[0].0[..],
1322 &[
1323 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, ][..]
1339 );
1340 }
1341
1342 #[fuchsia::test(allow_stalls = false)]
1343 async fn ap_handle_mlme_req_handle_mlme_disassoc_req() {
1344 let (mut ap, fake_device_state, _) = make_ap().await;
1345 ap.bss.replace(
1346 InfraBss::new(
1347 &mut ap.ctx,
1348 Ssid::try_from("coolnet").unwrap(),
1349 TimeUnit::DEFAULT_BEACON_INTERVAL,
1350 2,
1351 CapabilityInfo(0),
1352 vec![0b11111000],
1353 1,
1354 None,
1355 )
1356 .await
1357 .expect("expected InfraBss::new ok"),
1358 );
1359 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1360
1361 ap.handle_mlme_req(wlan_sme::MlmeRequest::Disassociate(fidl_mlme::DisassociateRequest {
1362 peer_sta_address: CLIENT_ADDR.to_array(),
1363 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDisassoc,
1364 }))
1365 .await
1366 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::DisassociateReq) ok");
1367 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1368 assert_eq!(
1369 &fake_device_state.lock().wlan_queue[0].0[..],
1370 &[
1371 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, ][..]
1381 );
1382 }
1383
1384 #[fuchsia::test(allow_stalls = false)]
1385 async fn ap_handle_mlme_req_handle_mlme_set_controlled_port_req() {
1386 let (mut ap, _, _) = make_ap().await;
1387 ap.bss.replace(
1388 InfraBss::new(
1389 &mut ap.ctx,
1390 Ssid::try_from("coolnet").unwrap(),
1391 TimeUnit::DEFAULT_BEACON_INTERVAL,
1392 2,
1393 CapabilityInfo(0),
1394 vec![0b11111000],
1395 1,
1396 Some(fake_wpa2_rsne()),
1397 )
1398 .await
1399 .expect("expected InfraBss::new ok"),
1400 );
1401 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1402
1403 ap.handle_mlme_req(wlan_sme::MlmeRequest::AssocResponse(fidl_mlme::AssociateResponse {
1404 peer_sta_address: CLIENT_ADDR.to_array(),
1405 result_code: fidl_mlme::AssociateResultCode::Success,
1406 association_id: 1,
1407 capability_info: CapabilityInfo(0).raw(),
1408 rates: vec![1, 2, 3],
1409 }))
1410 .await
1411 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::AssociateResp) ok");
1412
1413 ap.handle_mlme_req(wlan_sme::MlmeRequest::SetCtrlPort(
1414 fidl_mlme::SetControlledPortRequest {
1415 peer_sta_address: CLIENT_ADDR.to_array(),
1416 state: fidl_mlme::ControlledPortState::Open,
1417 },
1418 ))
1419 .await
1420 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::SetControlledPort) ok");
1421 }
1422
1423 #[fuchsia::test(allow_stalls = false)]
1424 async fn ap_handle_mlme_req_handle_mlme_eapol_req() {
1425 let (mut ap, fake_device_state, _) = make_ap().await;
1426 ap.bss.replace(
1427 InfraBss::new(
1428 &mut ap.ctx,
1429 Ssid::try_from("coolnet").unwrap(),
1430 TimeUnit::DEFAULT_BEACON_INTERVAL,
1431 2,
1432 CapabilityInfo(0),
1433 vec![0b11111000],
1434 1,
1435 None,
1436 )
1437 .await
1438 .expect("expected InfraBss::new ok"),
1439 );
1440 ap.bss.as_mut().unwrap().clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1441
1442 ap.handle_mlme_req(wlan_sme::MlmeRequest::Eapol(fidl_mlme::EapolRequest {
1443 dst_addr: CLIENT_ADDR.to_array(),
1444 src_addr: BSSID.to_array(),
1445 data: vec![1, 2, 3],
1446 }))
1447 .await
1448 .expect("expected Ap::handle_mlme_msg(fidl_mlme::MlmeRequest::EapolReq) ok");
1449 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1450 assert_eq!(
1451 &fake_device_state.lock().wlan_queue[0].0[..],
1452 &[
1453 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,
1465 ][..]
1466 );
1467 }
1468
1469 #[fuchsia::test(allow_stalls = false)]
1470 async fn ap_mlme_respond_to_query_device_info() {
1471 let (mut ap, _, _) = make_ap().await;
1472
1473 let (responder, receiver) = Responder::new();
1474 assert_variant!(
1475 ap.handle_mlme_req(wlan_sme::MlmeRequest::QueryDeviceInfo(responder)).await,
1476 Ok(())
1477 );
1478 assert_eq!(
1479 receiver.await.unwrap(),
1480 fidl_mlme::DeviceInfo {
1481 sta_addr: BSSID.to_array(),
1482 role: fidl_common::WlanMacRole::Ap,
1483 bands: test_utils::fake_mlme_band_caps(),
1484 softmac_hardware_capability: 0,
1485 qos_capable: false,
1486 }
1487 );
1488 }
1489
1490 #[fuchsia::test(allow_stalls = false)]
1491 async fn ap_mlme_respond_to_query_discovery_support() {
1492 let (mut ap, _, _) = make_ap().await;
1493
1494 let (responder, receiver) = Responder::new();
1495 assert_variant!(
1496 ap.handle_mlme_req(wlan_sme::MlmeRequest::QueryDiscoverySupport(responder)).await,
1497 Ok(())
1498 );
1499 let resp = receiver.await.unwrap();
1500 assert_eq!(resp.scan_offload.supported, true);
1501 assert_eq!(resp.probe_response_offload.supported, false);
1502 }
1503
1504 #[fuchsia::test(allow_stalls = false)]
1505 async fn ap_mlme_respond_to_query_mac_sublayer_support() {
1506 let (mut ap, _, _) = make_ap().await;
1507
1508 let (responder, receiver) = Responder::new();
1509 assert_variant!(
1510 ap.handle_mlme_req(wlan_sme::MlmeRequest::QueryMacSublayerSupport(responder)).await,
1511 Ok(())
1512 );
1513 let resp = receiver.await.unwrap();
1514 assert_eq!(resp.rate_selection_offload.supported, false);
1515 assert_eq!(resp.data_plane.data_plane_type, fidl_common::DataPlaneType::EthernetDevice);
1516 assert_eq!(resp.device.is_synthetic, true);
1517 assert_eq!(
1518 resp.device.mac_implementation_type,
1519 fidl_common::MacImplementationType::Softmac
1520 );
1521 assert_eq!(resp.device.tx_status_report_supported, true);
1522 }
1523
1524 #[fuchsia::test(allow_stalls = false)]
1525 async fn ap_mlme_respond_to_query_security_support() {
1526 let (mut ap, _, _) = make_ap().await;
1527
1528 let (responder, receiver) = Responder::new();
1529 assert_variant!(
1530 ap.handle_mlme_req(wlan_sme::MlmeRequest::QuerySecuritySupport(responder)).await,
1531 Ok(())
1532 );
1533 let resp = receiver.await.unwrap();
1534 assert_eq!(resp.mfp.supported, false);
1535 assert_eq!(resp.sae.driver_handler_supported, false);
1536 assert_eq!(resp.sae.sme_handler_supported, false);
1537 }
1538
1539 #[fuchsia::test(allow_stalls = false)]
1540 async fn ap_mlme_respond_to_query_spectrum_management_support() {
1541 let (mut ap, _, _) = make_ap().await;
1542
1543 let (responder, receiver) = Responder::new();
1544 assert_variant!(
1545 ap.handle_mlme_req(wlan_sme::MlmeRequest::QuerySpectrumManagementSupport(responder))
1546 .await,
1547 Ok(())
1548 );
1549 assert_eq!(receiver.await.unwrap().dfs.supported, true);
1550 }
1551
1552 #[test]
1553 fn display_rejection() {
1554 assert_eq!(format!("{}", Rejection::BadDsBits), "BadDsBits");
1555 }
1556}