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