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