1use crate::WlanTxPacketExt as _;
6use crate::ap::remote_client::{ClientRejection, RemoteClient};
7use crate::ap::{BeaconOffloadParams, BufferedFrame, Context, Rejection, TimedEvent, frame_writer};
8use crate::ddk_converter::softmac_key_configuration_from_mlme;
9use crate::device::{self, DeviceOps};
10use crate::error::Error;
11use anyhow::format_err;
12use fdf::ArenaStaticBox;
13use ieee80211::{MacAddr, MacAddrBytes, Ssid};
14use log::error;
15use std::collections::{HashMap, VecDeque};
16use std::fmt::Display;
17use wlan_common::mac::{self, CapabilityInfo, EthernetIIHdr};
18use wlan_common::{TimeUnit, ie, tim};
19use zerocopy::SplitByteSlice;
20use {
21 fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211, fidl_fuchsia_wlan_mlme as fidl_mlme,
22 fidl_fuchsia_wlan_softmac as fidl_softmac, fuchsia_trace as trace,
23};
24
25pub struct InfraBss {
26 pub ssid: Ssid,
27 pub rsne: Option<Vec<u8>>,
28 pub beacon_interval: TimeUnit,
29 pub dtim_period: u8,
30 pub capabilities: CapabilityInfo,
31 pub rates: Vec<u8>,
32 pub channel: u8,
33 pub clients: HashMap<MacAddr, RemoteClient>,
34
35 group_buffered: VecDeque<BufferedFrame>,
36 dtim_count: u8,
37}
38
39fn get_client_mut(
40 clients: &mut HashMap<MacAddr, RemoteClient>,
41 addr: MacAddr,
42) -> Result<&mut RemoteClient, Error> {
43 clients
44 .get_mut(&addr)
45 .ok_or(Error::Status(format!("client {:02X?} not found", addr), zx::Status::NOT_FOUND))
46}
47
48fn make_client_error(addr: MacAddr, e: Error) -> Error {
53 Error::Status(format!("client {}: {}", addr, e), e.into())
54}
55
56impl InfraBss {
57 pub async fn new<D: DeviceOps>(
58 ctx: &mut Context<D>,
59 ssid: Ssid,
60 beacon_interval: TimeUnit,
61 dtim_period: u8,
62 capabilities: CapabilityInfo,
63 rates: Vec<u8>,
64 channel: u8,
65 rsne: Option<Vec<u8>>,
66 ) -> Result<Self, Error> {
67 let bss = Self {
68 ssid,
69 rsne,
70 beacon_interval,
71 dtim_period,
72 rates,
73 capabilities,
74 channel,
75 clients: HashMap::new(),
76
77 group_buffered: VecDeque::new(),
78 dtim_count: 0,
79 };
80
81 ctx.device
82 .set_channel(fidl_ieee80211::WlanChannel {
83 primary: channel,
84
85 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
87 secondary80: 0,
88 })
89 .await
90 .map_err(|s| Error::Status(format!("failed to set channel"), s))?;
91
92 let (in_buffer, beacon_offload_params) = bss.make_beacon_frame(ctx)?;
95 let mac_frame = in_buffer.to_vec();
96 let tim_ele_offset = u64::try_from(beacon_offload_params.tim_ele_offset).map_err(|_| {
97 Error::Internal(format_err!(
98 "failed to convert TIM offset for beacon frame packet template"
99 ))
100 })?;
101 ctx.device
102 .enable_beaconing(fidl_softmac::WlanSoftmacBaseEnableBeaconingRequest {
103 packet_template: Some(fidl_softmac::WlanTxPacket::template(mac_frame)),
104 tim_ele_offset: Some(tim_ele_offset),
105 beacon_interval: Some(beacon_interval.0),
106 ..Default::default()
107 })
108 .await
109 .map_err(|s| Error::Status(format!("failed to enable beaconing"), s))?;
110 ctx.device
111 .set_ethernet_up()
112 .await
113 .map_err(|s| Error::Status(format!("Failed to set ethernet status to UP"), s))?;
114
115 Ok(bss)
116 }
117
118 pub async fn stop<D: DeviceOps>(&self, ctx: &mut Context<D>) -> Result<(), Error> {
119 ctx.device
120 .set_ethernet_down()
121 .await
122 .map_err(|s| Error::Status(format!("Failed to set ethernet status to DOWN"), s))?;
123 ctx.device
124 .disable_beaconing()
125 .await
126 .map_err(|s| Error::Status(format!("failed to disable beaconing"), s))
127 }
128
129 fn make_tim(&self) -> tim::TrafficIndicationMap {
130 let mut tim = tim::TrafficIndicationMap::new();
131 for client in self.clients.values() {
132 let aid = match client.aid() {
133 Some(aid) => aid,
134 None => {
135 continue;
136 }
137 };
138 tim.set_traffic_buffered(aid, client.has_buffered_frames());
139 }
140 tim
141 }
142
143 pub async fn handle_mlme_setkeys_req<D: DeviceOps>(
144 &mut self,
145 ctx: &mut Context<D>,
146 keylist: Vec<fidl_mlme::SetKeyDescriptor>,
147 ) -> Result<(), Error> {
148 fn key_type_name(key_type: fidl_mlme::KeyType) -> impl Display {
149 match key_type {
150 fidl_mlme::KeyType::Group => "GTK",
151 fidl_mlme::KeyType::Pairwise => "PTK",
152 fidl_mlme::KeyType::PeerKey => "peer key",
153 fidl_mlme::KeyType::Igtk => "IGTK",
154 }
155 }
156
157 if self.rsne.is_none() {
158 return Err(Error::Status(
159 format!("cannot set keys for an unprotected BSS"),
160 zx::Status::BAD_STATE,
161 ));
162 }
163
164 for key_descriptor in keylist.into_iter() {
165 let key_type = key_descriptor.key_type;
166 ctx.device
167 .install_key(&softmac_key_configuration_from_mlme(key_descriptor))
168 .await
169 .map_err(|status| {
170 Error::Status(
171 format!("failed to set {} on PHY", key_type_name(key_type)),
172 status,
173 )
174 })?;
175 }
176 Ok(())
177 }
178
179 pub async fn handle_mlme_auth_resp<D: DeviceOps>(
180 &mut self,
181 ctx: &mut Context<D>,
182 resp: fidl_mlme::AuthenticateResponse,
183 ) -> Result<(), Error> {
184 let client = get_client_mut(&mut self.clients, resp.peer_sta_address.into())?;
185 client
186 .handle_mlme_auth_resp(ctx, resp.result_code)
187 .await
188 .map_err(|e| make_client_error(client.addr, e))
189 }
190
191 pub async fn handle_mlme_deauth_req<D: DeviceOps>(
192 &mut self,
193 ctx: &mut Context<D>,
194 req: fidl_mlme::DeauthenticateRequest,
195 ) -> Result<(), Error> {
196 let client = get_client_mut(&mut self.clients, req.peer_sta_address.into())?;
197 client
198 .handle_mlme_deauth_req(ctx, req.reason_code)
199 .await
200 .map_err(|e| make_client_error(client.addr, e))?;
201 if client.deauthenticated() {
202 self.clients.remove(&req.peer_sta_address.into());
203 }
204 Ok(())
205 }
206
207 pub async fn handle_mlme_assoc_resp<D: DeviceOps>(
208 &mut self,
209 ctx: &mut Context<D>,
210 resp: fidl_mlme::AssociateResponse,
211 ) -> Result<(), Error> {
212 let client = get_client_mut(&mut self.clients, resp.peer_sta_address.into())?;
213
214 client
215 .handle_mlme_assoc_resp(
216 ctx,
217 self.rsne.is_some(),
218 self.channel,
219 CapabilityInfo(resp.capability_info),
220 resp.result_code,
221 resp.association_id,
222 &resp.rates,
223 )
224 .await
225 .map_err(|e| make_client_error(client.addr, e))
226 }
227
228 pub async fn handle_mlme_disassoc_req<D: DeviceOps>(
229 &mut self,
230 ctx: &mut Context<D>,
231 req: fidl_mlme::DisassociateRequest,
232 ) -> Result<(), Error> {
233 let client = get_client_mut(&mut self.clients, req.peer_sta_address.into())?;
234 client
235 .handle_mlme_disassoc_req(ctx, req.reason_code.into_primitive())
236 .await
237 .map_err(|e| make_client_error(client.addr, e))
238 }
239
240 pub fn handle_mlme_set_controlled_port_req(
241 &mut self,
242 req: fidl_mlme::SetControlledPortRequest,
243 ) -> Result<(), Error> {
244 let client = get_client_mut(&mut self.clients, req.peer_sta_address.into())?;
245 client
246 .handle_mlme_set_controlled_port_req(req.state)
247 .map_err(|e| make_client_error(client.addr, e))
248 }
249
250 pub fn handle_mlme_eapol_req<D: DeviceOps>(
251 &mut self,
252 ctx: &mut Context<D>,
253 req: fidl_mlme::EapolRequest,
254 ) -> Result<(), Error> {
255 let client = get_client_mut(&mut self.clients, req.dst_addr.into())?;
256 match client
257 .handle_mlme_eapol_req(ctx, req.src_addr.into(), &req.data)
258 .map_err(|e| make_client_error(client.addr, e))
259 {
260 Ok(()) => {
261 ctx.send_mlme_eapol_conf(fidl_mlme::EapolResultCode::Success, req.dst_addr.into())
262 }
263 Err(e) => {
264 if let Err(e) = ctx.send_mlme_eapol_conf(
265 fidl_mlme::EapolResultCode::TransmissionFailure,
266 req.dst_addr.into(),
267 ) {
268 error!("Failed to send eapol transmission failure: {:?}", e);
269 }
270 Err(e)
271 }
272 }
273 }
274
275 fn make_beacon_frame<D>(
276 &self,
277 ctx: &Context<D>,
278 ) -> Result<(ArenaStaticBox<[u8]>, BeaconOffloadParams), Error> {
279 let tim = self.make_tim();
280 let (pvb_offset, pvb_bitmap) = tim.make_partial_virtual_bitmap();
281
282 ctx.make_beacon_frame(
283 self.beacon_interval,
284 self.capabilities,
285 &self.ssid,
286 &self.rates,
287 self.channel,
288 ie::TimHeader {
289 dtim_count: self.dtim_count,
290 dtim_period: self.dtim_period,
291 bmp_ctrl: ie::BitmapControl(0)
292 .with_group_traffic(!self.group_buffered.is_empty())
293 .with_offset(pvb_offset),
294 },
295 pvb_bitmap,
296 self.rsne.as_ref().map_or(&[], |rsne| &rsne),
297 )
298 }
299
300 fn handle_probe_req<D: DeviceOps>(
301 &mut self,
302 ctx: &mut Context<D>,
303 client_addr: MacAddr,
304 ) -> Result<(), Rejection> {
305 let buffer = ctx
309 .make_probe_resp_frame(
310 client_addr,
311 self.beacon_interval,
312 self.capabilities,
313 &self.ssid,
314 &self.rates,
315 self.channel,
316 self.rsne.as_ref().map_or(&[], |rsne| &rsne),
317 )
318 .map_err(|e| Rejection::Client(client_addr, ClientRejection::WlanSendError(e)))?;
319 ctx.device.send_wlan_frame(buffer, fidl_softmac::WlanTxInfoFlags::empty(), None).map_err(
320 |s| {
321 Rejection::Client(
322 client_addr,
323 ClientRejection::WlanSendError(Error::Status(
324 format!("failed to send probe resp"),
325 s,
326 )),
327 )
328 },
329 )
330 }
331
332 pub async fn handle_mgmt_frame<B: SplitByteSlice, D: DeviceOps>(
333 &mut self,
334 ctx: &mut Context<D>,
335 mgmt_frame: mac::MgmtFrame<B>,
336 ) -> Result<(), Rejection> {
337 let frame_ctrl = mgmt_frame.frame_ctrl();
338 if frame_ctrl.to_ds() || frame_ctrl.from_ds() {
339 return Err(Rejection::BadDsBits);
342 }
343
344 let to_bss = mgmt_frame.mgmt_hdr.addr1.as_array() == ctx.bssid.as_array()
345 && mgmt_frame.mgmt_hdr.addr3.as_array() == ctx.bssid.as_array();
346 let client_addr = mgmt_frame.mgmt_hdr.addr2;
347
348 if mgmt_frame.mgmt_subtype() == mac::MgmtSubtype::PROBE_REQ {
349 if device::try_query_discovery_support(&mut ctx.device)
350 .await
351 .map_err(anyhow::Error::from)?
352 .probe_response_offload
353 .supported
354 {
355 return Err(Rejection::Error(format_err!(
357 "driver indicates probe response offload but MLME received a probe response!"
358 )));
359 }
360
361 if to_bss
362 || (mgmt_frame.mgmt_hdr.addr1 == ieee80211::BROADCAST_ADDR
363 && mgmt_frame.mgmt_hdr.addr3 == ieee80211::BROADCAST_ADDR)
364 {
365 for (id, ie_body) in mgmt_frame.into_ies().1 {
367 match id {
368 ie::Id::SSID => {
369 if !ie_body.is_empty() && *ie_body != self.ssid[..] {
370 return Err(Rejection::OtherBss);
372 }
373 }
374 _ => {}
375 }
376 }
377
378 return self.handle_probe_req(ctx, client_addr);
381 } else {
382 return Err(Rejection::OtherBss);
384 }
385 } else if !to_bss {
386 return Err(Rejection::OtherBss);
388 }
389
390 let mut new_client = None;
394 let client = match self.clients.get_mut(&client_addr) {
395 Some(client) => client,
396 None => new_client.get_or_insert_with(|| RemoteClient::new(client_addr)),
397 };
398
399 if let Err(e) = client
400 .handle_mgmt_frame(ctx, self.capabilities, Some(self.ssid.clone()), mgmt_frame)
401 .await
402 {
403 return Err(Rejection::Client(client_addr, e));
404 }
405
406 match client.set_power_state(ctx, frame_ctrl.power_mgmt()) {
409 Err(ClientRejection::NotAssociated) => {
410 error!("client {:02X?} tried to doze but is not associated", client_addr);
411 }
412 Err(e) => {
413 return Err(Rejection::Client(client.addr, e));
414 }
415 Ok(()) => {}
416 }
417
418 if client.deauthenticated() {
419 if new_client.is_none() {
420 self.clients.remove(&client_addr);
423 }
424 } else {
425 if let Some(client) = new_client.take() {
427 self.clients.insert(client_addr, client);
428 }
429 }
430
431 Ok(())
432 }
433
434 pub fn handle_data_frame<B: SplitByteSlice, D: DeviceOps>(
438 &mut self,
439 ctx: &mut Context<D>,
440 data_frame: mac::DataFrame<B>,
441 ) -> Result<(), Rejection> {
442 if mac::data_receiver_addr(&data_frame.fixed_fields).as_array() != ctx.bssid.as_array() {
443 return Err(Rejection::OtherBss);
445 }
446
447 let frame_ctrl = data_frame.frame_ctrl();
448 if !*&frame_ctrl.to_ds() || *&frame_ctrl.from_ds() {
449 return Err(Rejection::BadDsBits);
452 }
453
454 let src_addr =
455 mac::data_src_addr(&data_frame.fixed_fields, data_frame.addr4.as_deref().copied())
456 .ok_or(Rejection::NoSrcAddr)?;
457
458 let mut maybe_client = None;
461 let client = self
462 .clients
463 .get_mut(&src_addr)
464 .unwrap_or_else(|| maybe_client.get_or_insert_with(|| RemoteClient::new(src_addr)));
465
466 client.handle_data_frame(ctx, data_frame).map_err(|e| Rejection::Client(client.addr, e))?;
467
468 match client.set_power_state(ctx, frame_ctrl.power_mgmt()) {
471 Err(ClientRejection::NotAssociated) => {
472 error!("client {:02X?} tried to doze but is not associated", client.addr);
473 }
474 Err(e) => {
475 return Err(Rejection::Client(client.addr, e));
476 }
477 Ok(()) => {}
478 }
479
480 Ok(())
481 }
482
483 pub fn handle_ctrl_frame<B: SplitByteSlice, D: DeviceOps>(
484 &mut self,
485 ctx: &mut Context<D>,
486 ctrl_frame: mac::CtrlFrame<B>,
487 ) -> Result<(), Rejection> {
488 match ctrl_frame.try_into_ctrl_body().ok_or(Rejection::FrameMalformed)? {
489 mac::CtrlBody::PsPoll { ps_poll } => {
490 let client = match self.clients.get_mut(&ps_poll.ta) {
491 Some(client) => client,
492 _ => {
493 return Err(Rejection::Client(
494 ps_poll.ta,
495 ClientRejection::NotAuthenticated,
496 ));
497 }
498 };
499
500 const PS_POLL_MASK: u16 = 0b11000000_00000000;
503 client
504 .handle_ps_poll(ctx, ps_poll.masked_aid & !PS_POLL_MASK)
505 .map_err(|e| Rejection::Client(client.addr, e))
506 }
507 _ => Err(Rejection::FrameMalformed),
508 }
509 }
510
511 pub fn handle_multicast_eth_frame<D: DeviceOps>(
512 &mut self,
513 ctx: &mut Context<D>,
514 hdr: EthernetIIHdr,
515 body: &[u8],
516 async_id: trace::Id,
517 ) -> Result<(), Rejection> {
518 let buffer = ctx
519 .make_data_frame(
520 hdr.da,
521 hdr.sa,
522 self.rsne.is_some(),
523 false, hdr.ether_type.get(),
525 body,
526 )
527 .map_err(|e| Rejection::Client(hdr.da, ClientRejection::WlanSendError(e)))?;
528 let tx_flags = fidl_softmac::WlanTxInfoFlags::empty();
529
530 if !self.clients.values().any(|client| client.dozing()) {
531 ctx.device.send_wlan_frame(buffer, tx_flags, Some(async_id)).map_err(move |s| {
532 Rejection::Client(
533 hdr.da,
534 ClientRejection::WlanSendError(Error::Status(
535 format!("error sending multicast data frame"),
536 s,
537 )),
538 )
539 })?;
540 } else {
541 self.group_buffered.push_back(BufferedFrame { buffer, tx_flags, async_id });
542 }
543
544 Ok(())
545 }
546
547 pub fn handle_eth_frame<D: DeviceOps>(
548 &mut self,
549 ctx: &mut Context<D>,
550 hdr: EthernetIIHdr,
551 body: &[u8],
552 async_id: trace::Id,
553 ) -> Result<(), Rejection> {
554 if hdr.da.is_multicast() {
555 return self.handle_multicast_eth_frame(ctx, hdr, body, async_id);
556 }
557
558 let mut maybe_client = None;
561 let client = self
562 .clients
563 .get_mut(&hdr.da)
564 .unwrap_or_else(|| maybe_client.get_or_insert_with(|| RemoteClient::new(hdr.da)));
565 client
566 .handle_eth_frame(ctx, hdr.da, hdr.sa, hdr.ether_type.get(), body, async_id)
567 .map_err(|e| Rejection::Client(client.addr, e))
568 }
569
570 #[allow(dead_code)]
572 pub fn handle_bcn_tx_complete_indication<D: DeviceOps>(
573 &mut self,
574 ctx: &mut Context<D>,
575 ) -> Result<(), Error> {
576 if self.dtim_count > 0 {
577 self.dtim_count -= 1;
578 return Ok(());
579 }
580
581 self.dtim_count = self.dtim_period;
582
583 let mut buffered = self.group_buffered.drain(..).peekable();
584 while let Some(BufferedFrame { mut buffer, tx_flags, async_id }) = buffered.next() {
585 if buffered.peek().is_some() {
586 frame_writer::set_more_data(&mut buffer[..])?;
587 }
588 ctx.device
589 .send_wlan_frame(buffer, tx_flags, Some(async_id))
590 .map_err(|s| Error::Status(format!("error sending buffered frame"), s))?;
591 }
592
593 Ok(())
594 }
595
596 pub async fn handle_timed_event<D: DeviceOps>(
600 &mut self,
601 ctx: &mut Context<D>,
602 event: TimedEvent,
603 ) -> Result<(), Rejection> {
604 match event {
605 TimedEvent::ClientEvent(addr, event) => {
606 let client = self.clients.get_mut(&addr).ok_or(Rejection::NoSuchClient(addr))?;
607 client.handle_event(ctx, event).await.map_err(|e| Rejection::Client(client.addr, e))
608 }
609 }
610 }
611}
612
613#[cfg(test)]
614mod tests {
615 use super::*;
616 use crate::ap::remote_client::ClientEvent;
617 use crate::device::{FakeDevice, FakeDeviceConfig, FakeDeviceState};
618 use assert_matches::assert_matches;
619 use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
620 use fuchsia_sync::Mutex;
621 use ieee80211::Bssid;
622 use std::sync::{Arc, LazyLock};
623 use test_case::test_case;
624 use wlan_common::mac::IntoBytesExt as _;
625 use wlan_common::test_utils::fake_frames::fake_wpa2_rsne;
626 use wlan_common::timer::{self, create_timer};
627 use zerocopy::byteorder::big_endian::U16 as BigEndianU16;
628
629 static CLIENT_ADDR: LazyLock<MacAddr> = LazyLock::new(|| [4u8; 6].into());
630 static BSSID: LazyLock<Bssid> = LazyLock::new(|| [2u8; 6].into());
631 static CLIENT_ADDR2: LazyLock<MacAddr> = LazyLock::new(|| [6u8; 6].into());
632 static REMOTE_ADDR: LazyLock<MacAddr> = LazyLock::new(|| [123u8; 6].into());
633
634 fn make_context(
635 fake_device: FakeDevice,
636 ) -> (Context<FakeDevice>, timer::EventStream<TimedEvent>) {
637 let (timer, time_stream) = create_timer();
638 (Context::new(fake_device, timer, *BSSID), time_stream)
639 }
640
641 async fn make_infra_bss(ctx: &mut Context<FakeDevice>) -> InfraBss {
642 InfraBss::new(
643 ctx,
644 Ssid::try_from("coolnet").unwrap(),
645 TimeUnit::DEFAULT_BEACON_INTERVAL,
646 2,
647 CapabilityInfo(0),
648 vec![0b11111000],
649 1,
650 None,
651 )
652 .await
653 .expect("expected InfraBss::new ok")
654 }
655
656 async fn make_protected_infra_bss(ctx: &mut Context<FakeDevice>) -> InfraBss {
657 InfraBss::new(
658 ctx,
659 Ssid::try_from("coolnet").unwrap(),
660 TimeUnit::DEFAULT_BEACON_INTERVAL,
661 2,
662 CapabilityInfo(0),
663 vec![0b11111000],
664 1,
665 Some(fake_wpa2_rsne()),
666 )
667 .await
668 .expect("expected InfraBss::new ok")
669 }
670
671 #[fuchsia::test(allow_stalls = false)]
672 async fn new() {
673 let (fake_device, fake_device_state) = FakeDevice::new().await;
674 let (mut ctx, _) = make_context(fake_device);
675 InfraBss::new(
676 &mut ctx,
677 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
678 TimeUnit::DEFAULT_BEACON_INTERVAL,
679 2,
680 CapabilityInfo(0).with_ess(true),
681 vec![0b11111000],
682 1,
683 None,
684 )
685 .await
686 .expect("expected InfraBss::new ok");
687
688 assert_eq!(
689 fake_device_state.lock().wlan_channel,
690 fidl_ieee80211::WlanChannel {
691 primary: 1,
692 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
693 secondary80: 0
694 }
695 );
696
697 let beacon_tmpl = vec![
698 0b10000000, 0, 0, 0, 255, 255, 255, 255, 255, 255, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 1, 0, 0, 5, 1, 2, 3, 4, 5, 1, 1, 0b11111000, 3, 1, 1, 5, 4, 0, 2, 0, 0, ];
715
716 assert_eq!(
717 fake_device_state.lock().beacon_config.as_ref().expect("expected beacon_config"),
718 &(beacon_tmpl, 49, TimeUnit::DEFAULT_BEACON_INTERVAL)
719 );
720 }
721
722 #[fuchsia::test(allow_stalls = false)]
723 async fn stop() {
724 let (fake_device, fake_device_state) = FakeDevice::new().await;
725 let (mut ctx, _) = make_context(fake_device);
726 let bss = make_infra_bss(&mut ctx).await;
727 bss.stop(&mut ctx).await.expect("expected InfraBss::stop ok");
728 assert!(fake_device_state.lock().beacon_config.is_none());
729 }
730
731 #[fuchsia::test(allow_stalls = false)]
732 async fn handle_mlme_auth_resp() {
733 let (fake_device, fake_device_state) = FakeDevice::new().await;
734 let (mut ctx, _) = make_context(fake_device);
735 let mut bss = make_infra_bss(&mut ctx).await;
736
737 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
738
739 bss.handle_mlme_auth_resp(
740 &mut ctx,
741 fidl_mlme::AuthenticateResponse {
742 peer_sta_address: CLIENT_ADDR.to_array(),
743 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
744 },
745 )
746 .await
747 .expect("expected InfraBss::handle_mlme_auth_resp ok");
748 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
749 assert_eq!(
750 &fake_device_state.lock().wlan_queue[0].0[..],
751 &[
752 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, ][..]
764 );
765 }
766
767 #[fuchsia::test(allow_stalls = false)]
768 async fn handle_mlme_auth_resp_no_such_client() {
769 let (fake_device, _) = FakeDevice::new().await;
770 let (mut ctx, _) = make_context(fake_device);
771 let mut bss = make_infra_bss(&mut ctx).await;
772
773 assert_eq!(
774 zx::Status::from(
775 bss.handle_mlme_auth_resp(
776 &mut ctx,
777 fidl_mlme::AuthenticateResponse {
778 peer_sta_address: CLIENT_ADDR.to_array(),
779 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
780 },
781 )
782 .await
783 .expect_err("expected InfraBss::handle_mlme_auth_resp error")
784 ),
785 zx::Status::NOT_FOUND
786 );
787 }
788
789 #[fuchsia::test(allow_stalls = false)]
790 async fn handle_mlme_deauth_req() {
791 let (fake_device, fake_device_state) = FakeDevice::new().await;
792 let (mut ctx, _) = make_context(fake_device);
793 let mut bss = make_infra_bss(&mut ctx).await;
794
795 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
796
797 bss.handle_mlme_deauth_req(
798 &mut ctx,
799 fidl_mlme::DeauthenticateRequest {
800 peer_sta_address: CLIENT_ADDR.to_array(),
801 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
802 },
803 )
804 .await
805 .expect("expected InfraBss::handle_mlme_deauth_req ok");
806 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
807 assert_eq!(
808 &fake_device_state.lock().wlan_queue[0].0[..],
809 &[
810 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, ][..]
820 );
821
822 assert!(!bss.clients.contains_key(&CLIENT_ADDR));
823 }
824
825 #[fuchsia::test(allow_stalls = false)]
826 async fn handle_mlme_assoc_resp() {
827 let (fake_device, fake_device_state) = FakeDevice::new().await;
828 let (mut ctx, _) = make_context(fake_device);
829 let mut bss = make_infra_bss(&mut ctx).await;
830
831 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
832 bss.handle_mlme_assoc_resp(
833 &mut ctx,
834 fidl_mlme::AssociateResponse {
835 peer_sta_address: CLIENT_ADDR.to_array(),
836 result_code: fidl_mlme::AssociateResultCode::Success,
837 association_id: 1,
838 capability_info: 0,
839 rates: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
840 },
841 )
842 .await
843 .expect("expected InfraBss::handle_mlme_assoc_resp ok");
844 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
845 assert_eq!(
846 &fake_device_state.lock().wlan_queue[0].0[..],
847 &[
848 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, ][..]
864 );
865 assert!(fake_device_state.lock().assocs.contains_key(&CLIENT_ADDR));
866 }
867
868 #[fuchsia::test(allow_stalls = false)]
869 async fn handle_mlme_assoc_resp_with_caps() {
870 let (fake_device, fake_device_state) = FakeDevice::new().await;
871 let (mut ctx, _) = make_context(fake_device);
872 let mut bss = InfraBss::new(
873 &mut ctx,
874 Ssid::try_from("coolnet").unwrap(),
875 TimeUnit::DEFAULT_BEACON_INTERVAL,
876 2,
877 CapabilityInfo(0).with_short_preamble(true).with_ess(true),
878 vec![0b11111000],
879 1,
880 None,
881 )
882 .await
883 .expect("expected InfraBss::new ok");
884
885 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
886
887 bss.handle_mlme_assoc_resp(
888 &mut ctx,
889 fidl_mlme::AssociateResponse {
890 peer_sta_address: CLIENT_ADDR.to_array(),
891 result_code: fidl_mlme::AssociateResultCode::Success,
892 association_id: 1,
893 capability_info: CapabilityInfo(0).with_short_preamble(true).raw(),
894 rates: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
895 },
896 )
897 .await
898 .expect("expected InfraBss::handle_mlme_assoc_resp ok");
899 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
900 assert_eq!(
901 &fake_device_state.lock().wlan_queue[0].0[..],
902 &[
903 0b00010000, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 0b00100000, 0b00000000, 0, 0, 1, 0, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 2, 9, 10, 90, 3, 90, 0, 0, ][..]
919 );
920 assert!(fake_device_state.lock().assocs.contains_key(&CLIENT_ADDR));
921 }
922
923 #[fuchsia::test(allow_stalls = false)]
924 async fn handle_mlme_disassoc_req() {
925 let (fake_device, fake_device_state) = FakeDevice::new().await;
926 let (mut ctx, _) = make_context(fake_device);
927 let mut bss = make_infra_bss(&mut ctx).await;
928
929 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
930
931 bss.handle_mlme_disassoc_req(
932 &mut ctx,
933 fidl_mlme::DisassociateRequest {
934 peer_sta_address: CLIENT_ADDR.to_array(),
935 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDisassoc,
936 },
937 )
938 .await
939 .expect("expected InfraBss::handle_mlme_disassoc_req ok");
940 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
941 assert_eq!(
942 &fake_device_state.lock().wlan_queue[0].0[..],
943 &[
944 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, ][..]
954 );
955 }
956
957 #[fuchsia::test(allow_stalls = false)]
958 async fn handle_mlme_set_controlled_port_req() {
959 let (fake_device, _) = FakeDevice::new().await;
960 let (mut ctx, _) = make_context(fake_device);
961 let mut bss = make_protected_infra_bss(&mut ctx).await;
962
963 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
964
965 bss.handle_mlme_assoc_resp(
966 &mut ctx,
967 fidl_mlme::AssociateResponse {
968 peer_sta_address: CLIENT_ADDR.to_array(),
969 result_code: fidl_mlme::AssociateResultCode::Success,
970 association_id: 1,
971 capability_info: 0,
972 rates: vec![1, 2, 3],
973 },
974 )
975 .await
976 .expect("expected InfraBss::handle_mlme_assoc_resp ok");
977
978 bss.handle_mlme_set_controlled_port_req(fidl_mlme::SetControlledPortRequest {
979 peer_sta_address: CLIENT_ADDR.to_array(),
980 state: fidl_mlme::ControlledPortState::Open,
981 })
982 .expect("expected InfraBss::handle_mlme_set_controlled_port_req ok");
983 }
984
985 #[fuchsia::test(allow_stalls = false)]
986 async fn handle_mlme_eapol_req() {
987 let (fake_device, fake_device_state) = FakeDevice::new().await;
988 let (mut ctx, _) = make_context(fake_device);
989 let mut bss = make_infra_bss(&mut ctx).await;
990
991 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
992
993 bss.handle_mlme_eapol_req(
994 &mut ctx,
995 fidl_mlme::EapolRequest {
996 dst_addr: CLIENT_ADDR.to_array(),
997 src_addr: BSSID.to_array(),
998 data: vec![1, 2, 3],
999 },
1000 )
1001 .expect("expected InfraBss::handle_mlme_eapol_req ok");
1002 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1003 assert_eq!(
1004 &fake_device_state.lock().wlan_queue[0].0[..],
1005 &[
1006 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,
1018 ][..]
1019 );
1020
1021 let confirm = fake_device_state
1022 .lock()
1023 .next_mlme_msg::<fidl_mlme::EapolConfirm>()
1024 .expect("Did not receive valid Eapol Confirm msg");
1025 assert_eq!(confirm.result_code, fidl_mlme::EapolResultCode::Success);
1026 assert_eq!(&confirm.dst_addr, CLIENT_ADDR.as_array());
1027 }
1028
1029 #[fuchsia::test(allow_stalls = false)]
1030 async fn handle_mgmt_frame_auth() {
1031 let (fake_device, fake_device_state) = FakeDevice::new().await;
1032 let (mut ctx, _) = make_context(fake_device);
1033 let mut bss = make_infra_bss(&mut ctx).await;
1034
1035 bss.handle_mgmt_frame(
1036 &mut ctx,
1037 mac::MgmtFrame {
1038 mgmt_hdr: mac::MgmtHdr {
1039 frame_ctrl: mac::FrameControl(0)
1040 .with_frame_type(mac::FrameType::MGMT)
1041 .with_mgmt_subtype(mac::MgmtSubtype::AUTH),
1042 duration: 0,
1043 addr1: (*BSSID).into(),
1044 addr2: *CLIENT_ADDR,
1045 addr3: (*BSSID).into(),
1046 seq_ctrl: mac::SequenceControl(10),
1047 }
1048 .as_bytes_ref(),
1049 ht_ctrl: None,
1050 body: &[
1051 0, 0, 1, 0, 0, 0, ][..],
1056 },
1057 )
1058 .await
1059 .expect("expected OK");
1060
1061 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), true);
1062
1063 let msg = fake_device_state
1064 .lock()
1065 .next_mlme_msg::<fidl_mlme::AuthenticateIndication>()
1066 .expect("expected MLME message");
1067 assert_eq!(
1068 msg,
1069 fidl_mlme::AuthenticateIndication {
1070 peer_sta_address: CLIENT_ADDR.to_array(),
1071 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1072 },
1073 );
1074 }
1075
1076 #[fuchsia::test(allow_stalls = false)]
1077 async fn handle_mgmt_frame_assoc_req() {
1078 let (fake_device, fake_device_state) = FakeDevice::new().await;
1079 let (mut ctx, _) = make_context(fake_device);
1080 let mut bss = make_infra_bss(&mut ctx).await;
1081
1082 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1083 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1084 client
1085 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1086 .await
1087 .expect("expected OK");
1088
1089 bss.handle_mgmt_frame(
1090 &mut ctx,
1091 mac::MgmtFrame {
1092 mgmt_hdr: mac::MgmtHdr {
1093 frame_ctrl: mac::FrameControl(0)
1094 .with_frame_type(mac::FrameType::MGMT)
1095 .with_mgmt_subtype(mac::MgmtSubtype::ASSOC_REQ),
1096 duration: 0,
1097 addr1: (*BSSID).into(),
1098 addr2: *CLIENT_ADDR,
1099 addr3: (*BSSID).into(),
1100 seq_ctrl: mac::SequenceControl(10),
1101 }
1102 .as_bytes_ref(),
1103 ht_ctrl: None,
1104 body: &[
1105 0, 0, 10, 0, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 2, 9, 10, 48, 2, 77, 88, ][..],
1113 },
1114 )
1115 .await
1116 .expect("expected OK");
1117
1118 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), true);
1119
1120 let msg = fake_device_state
1121 .lock()
1122 .next_mlme_msg::<fidl_mlme::AssociateIndication>()
1123 .expect("expected MLME message");
1124 assert_eq!(
1125 msg,
1126 fidl_mlme::AssociateIndication {
1127 peer_sta_address: CLIENT_ADDR.to_array(),
1128 listen_interval: 10,
1129 ssid: Some(Ssid::try_from("coolnet").unwrap().into()),
1130 capability_info: 0,
1131 rates: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
1132 rsne: Some(vec![48, 2, 77, 88]),
1133 },
1134 );
1135 }
1136
1137 #[fuchsia::test(allow_stalls = false)]
1138 async fn handle_mgmt_frame_bad_ds_bits_to_ds() {
1139 let (fake_device, _) = FakeDevice::new().await;
1140 let (mut ctx, _) = make_context(fake_device);
1141 let mut bss = make_infra_bss(&mut ctx).await;
1142
1143 assert_matches!(
1144 bss.handle_mgmt_frame(
1145 &mut ctx,
1146 mac::MgmtFrame {
1147 mgmt_hdr: mac::MgmtHdr {
1148 frame_ctrl: mac::FrameControl(0)
1149 .with_frame_type(mac::FrameType::MGMT)
1150 .with_mgmt_subtype(mac::MgmtSubtype::AUTH)
1151 .with_to_ds(true),
1152 duration: 0,
1153 addr1: (*BSSID).into(),
1154 addr2: *CLIENT_ADDR,
1155 addr3: (*BSSID).into(),
1156 seq_ctrl: mac::SequenceControl(10),
1157 }
1158 .as_bytes_ref(),
1159 ht_ctrl: None,
1160 body: &[
1161 0, 0, 1, 0, 0, 0, ][..],
1166 },
1167 )
1168 .await
1169 .expect_err("expected error"),
1170 Rejection::BadDsBits
1171 );
1172
1173 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), false);
1174 }
1175
1176 #[fuchsia::test(allow_stalls = false)]
1177 async fn handle_mgmt_frame_bad_ds_bits_from_ds() {
1178 let (fake_device, _) = FakeDevice::new().await;
1179 let (mut ctx, _) = make_context(fake_device);
1180 let mut bss = make_infra_bss(&mut ctx).await;
1181
1182 assert_matches!(
1183 bss.handle_mgmt_frame(
1184 &mut ctx,
1185 mac::MgmtFrame {
1186 mgmt_hdr: mac::MgmtHdr {
1187 frame_ctrl: mac::FrameControl(0)
1188 .with_frame_type(mac::FrameType::MGMT)
1189 .with_mgmt_subtype(mac::MgmtSubtype::AUTH)
1190 .with_from_ds(true),
1191 duration: 0,
1192 addr1: (*BSSID).into(),
1193 addr2: *CLIENT_ADDR,
1194 addr3: (*BSSID).into(),
1195 seq_ctrl: mac::SequenceControl(10),
1196 }
1197 .as_bytes_ref(),
1198 ht_ctrl: None,
1199 body: &[
1200 0, 0, 1, 0, 0, 0, ][..],
1205 },
1206 )
1207 .await
1208 .expect_err("expected error"),
1209 Rejection::BadDsBits
1210 );
1211
1212 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), false);
1213 }
1214
1215 #[fuchsia::test(allow_stalls = false)]
1216 async fn handle_mgmt_frame_no_such_client() {
1217 let (fake_device, _) = FakeDevice::new().await;
1218 let (mut ctx, _) = make_context(fake_device);
1219 let mut bss = make_infra_bss(&mut ctx).await;
1220
1221 assert_matches!(
1222 bss.handle_mgmt_frame(
1223 &mut ctx,
1224 mac::MgmtFrame {
1225 mgmt_hdr: mac::MgmtHdr {
1226 frame_ctrl: mac::FrameControl(0)
1227 .with_frame_type(mac::FrameType::MGMT)
1228 .with_mgmt_subtype(mac::MgmtSubtype::DISASSOC),
1229 duration: 0,
1230 addr1: (*BSSID).into(),
1231 addr2: *CLIENT_ADDR,
1232 addr3: (*BSSID).into(),
1233 seq_ctrl: mac::SequenceControl(10),
1234 }
1235 .as_bytes_ref(),
1236 ht_ctrl: None,
1237 body: &[
1238 8, 0, ][..],
1241 },
1242 )
1243 .await
1244 .expect_err("expected error"),
1245 Rejection::Client(_, ClientRejection::NotPermitted)
1246 );
1247
1248 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), false);
1249 }
1250
1251 #[fuchsia::test(allow_stalls = false)]
1252 async fn handle_mgmt_frame_bogus() {
1253 let (fake_device, _) = FakeDevice::new().await;
1254 let (mut ctx, _) = make_context(fake_device);
1255 let mut bss = make_infra_bss(&mut ctx).await;
1256
1257 assert_matches!(
1258 bss.handle_mgmt_frame(
1259 &mut ctx,
1260 mac::MgmtFrame {
1261 mgmt_hdr: mac::MgmtHdr {
1262 frame_ctrl: mac::FrameControl(0)
1263 .with_frame_type(mac::FrameType::MGMT)
1264 .with_mgmt_subtype(mac::MgmtSubtype::AUTH),
1265 duration: 0,
1266 addr1: (*BSSID).into(),
1267 addr2: *CLIENT_ADDR,
1268 addr3: (*BSSID).into(),
1269 seq_ctrl: mac::SequenceControl(10),
1270 }
1271 .as_bytes_ref(),
1272 ht_ctrl: None,
1273 body: &[][..],
1275 },
1276 )
1277 .await
1278 .expect_err("expected error"),
1279 Rejection::Client(_, ClientRejection::ParseFailed)
1280 );
1281
1282 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), false);
1283 }
1284
1285 #[fuchsia::test(allow_stalls = false)]
1286 async fn handle_data_frame() {
1287 let (fake_device, fake_device_state) = FakeDevice::new().await;
1288 let (mut ctx, _) = make_context(fake_device);
1289 let mut bss = make_infra_bss(&mut ctx).await;
1290
1291 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1292 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1293
1294 client
1296 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1297 .await
1298 .expect("expected OK");
1299 client
1300 .handle_mlme_assoc_resp(
1301 &mut ctx,
1302 false,
1303 1,
1304 mac::CapabilityInfo(0),
1305 fidl_mlme::AssociateResultCode::Success,
1306 1,
1307 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1308 )
1309 .await
1310 .expect("expected OK");
1311
1312 bss.handle_data_frame(
1313 &mut ctx,
1314 mac::DataFrame {
1315 fixed_fields: mac::FixedDataHdrFields {
1316 frame_ctrl: mac::FrameControl(0)
1317 .with_frame_type(mac::FrameType::DATA)
1318 .with_to_ds(true),
1319 duration: 0,
1320 addr1: (*BSSID).into(),
1321 addr2: *CLIENT_ADDR,
1322 addr3: *CLIENT_ADDR2,
1323 seq_ctrl: mac::SequenceControl(10),
1324 }
1325 .as_bytes_ref(),
1326 addr4: None,
1327 qos_ctrl: None,
1328 ht_ctrl: None,
1329 body: &[
1330 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1335 ][..],
1336 },
1337 )
1338 .expect("expected OK");
1339
1340 assert_eq!(fake_device_state.lock().eth_queue.len(), 1);
1341 assert_eq!(
1342 &fake_device_state.lock().eth_queue[0][..],
1343 &[
1344 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 0x12, 0x34, 1, 2, 3, 4, 5,
1349 ][..]
1350 );
1351 }
1352
1353 #[fuchsia::test(allow_stalls = false)]
1354 async fn handle_data_frame_bad_ds_bits() {
1355 let (fake_device, fake_device_state) = FakeDevice::new().await;
1356 let (mut ctx, _) = make_context(fake_device);
1357 let mut bss = make_infra_bss(&mut ctx).await;
1358
1359 assert_matches!(
1360 bss.handle_data_frame(
1361 &mut ctx,
1362 mac::DataFrame {
1363 fixed_fields: mac::FixedDataHdrFields {
1364 frame_ctrl: mac::FrameControl(0)
1365 .with_frame_type(mac::FrameType::DATA)
1366 .with_to_ds(false),
1367 duration: 0,
1368 addr1: (*BSSID).into(),
1369 addr2: *CLIENT_ADDR,
1370 addr3: *CLIENT_ADDR2,
1371 seq_ctrl: mac::SequenceControl(10),
1372 }
1373 .as_bytes_ref(),
1374 addr4: None,
1375 qos_ctrl: None,
1376 ht_ctrl: None,
1377 body: &[
1378 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1383 ][..],
1384 },
1385 )
1386 .expect_err("expected error"),
1387 Rejection::BadDsBits
1388 );
1389
1390 assert_eq!(fake_device_state.lock().eth_queue.len(), 0);
1391 }
1392
1393 #[fuchsia::test(allow_stalls = false)]
1394 async fn handle_client_event() {
1395 let (fake_device, fake_device_state) = FakeDevice::new().await;
1396 let (mut ctx, mut time_stream) = make_context(fake_device);
1397 let mut bss = make_infra_bss(&mut ctx).await;
1398
1399 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1400 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1401
1402 client
1404 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1405 .await
1406 .expect("expected OK");
1407 client
1408 .handle_mlme_assoc_resp(
1409 &mut ctx,
1410 false,
1411 1,
1412 mac::CapabilityInfo(0),
1413 fidl_mlme::AssociateResultCode::Success,
1414 1,
1415 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1416 )
1417 .await
1418 .expect("expected OK");
1419
1420 fake_device_state.lock().wlan_queue.clear();
1421
1422 let _ = time_stream.try_next().unwrap().expect("Should have scheduled a timeout");
1423 bss.handle_timed_event(
1424 &mut ctx,
1425 TimedEvent::ClientEvent(*CLIENT_ADDR, ClientEvent::BssIdleTimeout),
1426 )
1427 .await
1428 .expect("expected OK");
1429
1430 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1432 #[rustfmt::skip]
1433 assert_eq!(&fake_device_state.lock().wlan_queue[0].0[..], &[
1434 0b10100000, 0, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x30, 0, 4, 0, ][..]);
1444
1445 let msg = fake_device_state
1446 .lock()
1447 .next_mlme_msg::<fidl_mlme::DisassociateIndication>()
1448 .expect("expected MLME message");
1449 assert_eq!(
1450 msg,
1451 fidl_mlme::DisassociateIndication {
1452 peer_sta_address: CLIENT_ADDR.to_array(),
1453 reason_code: fidl_ieee80211::ReasonCode::ReasonInactivity,
1454 locally_initiated: true,
1455 },
1456 );
1457 }
1458
1459 #[fuchsia::test(allow_stalls = false)]
1460 async fn handle_data_frame_no_such_client() {
1461 let (fake_device, fake_device_state) = FakeDevice::new().await;
1462 let (mut ctx, _) = make_context(fake_device);
1463 let mut bss = make_infra_bss(&mut ctx).await;
1464
1465 assert_matches!(
1466 bss.handle_data_frame(
1467 &mut ctx,
1468 mac::DataFrame {
1469 fixed_fields: mac::FixedDataHdrFields {
1470 frame_ctrl: mac::FrameControl(0)
1471 .with_frame_type(mac::FrameType::DATA)
1472 .with_to_ds(true),
1473 duration: 0,
1474 addr1: (*BSSID).into(),
1475 addr2: *CLIENT_ADDR,
1476 addr3: *CLIENT_ADDR2,
1477 seq_ctrl: mac::SequenceControl(10),
1478 }
1479 .as_bytes_ref(),
1480 addr4: None,
1481 qos_ctrl: None,
1482 ht_ctrl: None,
1483 body: &[
1484 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1489 ][..],
1490 },
1491 )
1492 .expect_err("expected error"),
1493 Rejection::Client(_, ClientRejection::NotPermitted)
1494 );
1495
1496 assert_eq!(fake_device_state.lock().eth_queue.len(), 0);
1497
1498 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1499 assert_eq!(
1500 fake_device_state.lock().wlan_queue[0].0,
1501 &[
1502 0b11000000, 0b00000000, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0, 7, 0, ][..]
1512 );
1513 }
1514
1515 #[fuchsia::test(allow_stalls = false)]
1516 async fn handle_data_frame_client_not_associated() {
1517 let (fake_device, fake_device_state) = FakeDevice::new().await;
1518 let (mut ctx, _) = make_context(fake_device);
1519 let mut bss = make_infra_bss(&mut ctx).await;
1520
1521 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1522 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1523
1524 client
1527 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1528 .await
1529 .expect("expected OK");
1530
1531 fake_device_state.lock().wlan_queue.clear();
1532
1533 assert_matches!(
1534 bss.handle_data_frame(
1535 &mut ctx,
1536 mac::DataFrame {
1537 fixed_fields: mac::FixedDataHdrFields {
1538 frame_ctrl: mac::FrameControl(0)
1539 .with_frame_type(mac::FrameType::DATA)
1540 .with_to_ds(true),
1541 duration: 0,
1542 addr1: (*BSSID).into(),
1543 addr2: *CLIENT_ADDR,
1544 addr3: *CLIENT_ADDR2,
1545 seq_ctrl: mac::SequenceControl(10),
1546 }
1547 .as_bytes_ref(),
1548 addr4: None,
1549 qos_ctrl: None,
1550 ht_ctrl: None,
1551 body: &[
1552 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1557 ][..],
1558 },
1559 )
1560 .expect_err("expected error"),
1561 Rejection::Client(_, ClientRejection::NotPermitted)
1562 );
1563
1564 assert_eq!(fake_device_state.lock().eth_queue.len(), 0);
1565
1566 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1567 assert_eq!(
1568 fake_device_state.lock().wlan_queue[0].0,
1569 &[
1570 0b10100000, 0b00000000, 0, 0, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x20, 0, 7, 0, ][..]
1580 );
1581 }
1582
1583 #[fuchsia::test(allow_stalls = false)]
1584 async fn handle_eth_frame_no_rsn() {
1585 let (fake_device, fake_device_state) = FakeDevice::new().await;
1586 let (mut ctx, _) = make_context(fake_device);
1587 let mut bss = make_infra_bss(&mut ctx).await;
1588 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1589
1590 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1591 client
1592 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1593 .await
1594 .expect("expected OK");
1595 client
1596 .handle_mlme_assoc_resp(
1597 &mut ctx,
1598 false,
1599 1,
1600 mac::CapabilityInfo(0),
1601 fidl_mlme::AssociateResultCode::Success,
1602 1,
1603 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1604 )
1605 .await
1606 .expect("expected OK");
1607 fake_device_state.lock().wlan_queue.clear();
1608
1609 bss.handle_eth_frame(
1610 &mut ctx,
1611 EthernetIIHdr {
1612 da: *CLIENT_ADDR,
1613 sa: *CLIENT_ADDR2,
1614 ether_type: BigEndianU16::new(0x1234),
1615 },
1616 &[1, 2, 3, 4, 5][..],
1617 0.into(),
1618 )
1619 .expect("expected OK");
1620
1621 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1622 assert_eq!(
1623 &fake_device_state.lock().wlan_queue[0].0[..],
1624 &[
1625 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,
1637 ][..]
1638 );
1639 }
1640
1641 #[fuchsia::test(allow_stalls = false)]
1642 async fn handle_eth_frame_no_client() {
1643 let (fake_device, fake_device_state) = FakeDevice::new().await;
1644 let (mut ctx, _) = make_context(fake_device);
1645 let mut bss = make_infra_bss(&mut ctx).await;
1646
1647 assert_matches!(
1648 bss.handle_eth_frame(
1649 &mut ctx,
1650 EthernetIIHdr {
1651 da: *CLIENT_ADDR,
1652 sa: *CLIENT_ADDR2,
1653 ether_type: BigEndianU16::new(0x1234)
1654 },
1655 &[1, 2, 3, 4, 5][..],
1656 0.into(),
1657 )
1658 .expect_err("expected error"),
1659 Rejection::Client(_, ClientRejection::NotAssociated)
1660 );
1661
1662 assert_eq!(fake_device_state.lock().wlan_queue.len(), 0);
1663 }
1664
1665 #[fuchsia::test(allow_stalls = false)]
1666 async fn handle_eth_frame_is_rsn_eapol_controlled_port_closed() {
1667 let (fake_device, fake_device_state) = FakeDevice::new().await;
1668 let (mut ctx, _) = make_context(fake_device);
1669 let mut bss = make_protected_infra_bss(&mut ctx).await;
1670 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1671
1672 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1673 client
1674 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1675 .await
1676 .expect("expected OK");
1677 client
1678 .handle_mlme_assoc_resp(
1679 &mut ctx,
1680 true,
1681 1,
1682 mac::CapabilityInfo(0),
1683 fidl_mlme::AssociateResultCode::Success,
1684 1,
1685 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1686 )
1687 .await
1688 .expect("expected OK");
1689 fake_device_state.lock().wlan_queue.clear();
1690
1691 assert_matches!(
1692 bss.handle_eth_frame(
1693 &mut ctx,
1694 EthernetIIHdr {
1695 da: *CLIENT_ADDR,
1696 sa: *CLIENT_ADDR2,
1697 ether_type: BigEndianU16::new(0x1234)
1698 },
1699 &[1, 2, 3, 4, 5][..],
1700 0.into(),
1701 )
1702 .expect_err("expected error"),
1703 Rejection::Client(_, ClientRejection::ControlledPortClosed)
1704 );
1705 }
1706
1707 #[fuchsia::test(allow_stalls = false)]
1708 async fn handle_eth_frame_is_rsn_eapol_controlled_port_open() {
1709 let (fake_device, fake_device_state) = FakeDevice::new().await;
1710 let (mut ctx, _) = make_context(fake_device);
1711 let mut bss = make_protected_infra_bss(&mut ctx).await;
1712 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1713
1714 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1715 client
1716 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1717 .await
1718 .expect("expected OK");
1719 client
1720 .handle_mlme_assoc_resp(
1721 &mut ctx,
1722 true,
1723 1,
1724 mac::CapabilityInfo(0),
1725 fidl_mlme::AssociateResultCode::Success,
1726 1,
1727 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1728 )
1729 .await
1730 .expect("expected OK");
1731 fake_device_state.lock().wlan_queue.clear();
1732
1733 client
1734 .handle_mlme_set_controlled_port_req(fidl_mlme::ControlledPortState::Open)
1735 .expect("expected OK");
1736
1737 bss.handle_eth_frame(
1738 &mut ctx,
1739 EthernetIIHdr {
1740 da: *CLIENT_ADDR,
1741 sa: *CLIENT_ADDR2,
1742 ether_type: BigEndianU16::new(0x1234),
1743 },
1744 &[1, 2, 3, 4, 5][..],
1745 0.into(),
1746 )
1747 .expect("expected OK");
1748
1749 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1750 assert_eq!(
1751 &fake_device_state.lock().wlan_queue[0].0[..],
1752 &[
1753 0b00001000, 0b01000010, 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,
1765 ][..]
1766 );
1767 }
1768
1769 #[test_case(false; "Controlled port closed")]
1770 #[test_case(true; "Controlled port open")]
1771 #[fuchsia::test(allow_stalls = false)]
1772 async fn handle_data_frame_is_rsn_eapol(controlled_port_open: bool) {
1773 let (fake_device, fake_device_state) = FakeDevice::new().await;
1774 let (mut ctx, _) = make_context(fake_device);
1775 let mut bss = make_protected_infra_bss(&mut ctx).await;
1776 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1777
1778 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1779 client
1780 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1781 .await
1782 .expect("expected OK");
1783 client
1784 .handle_mlme_assoc_resp(
1785 &mut ctx,
1786 true,
1787 1,
1788 mac::CapabilityInfo(0),
1789 fidl_mlme::AssociateResultCode::Success,
1790 1,
1791 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1792 )
1793 .await
1794 .expect("expected OK");
1795 fake_device_state.lock().wlan_queue.clear();
1796
1797 if controlled_port_open {
1798 client
1799 .handle_mlme_set_controlled_port_req(fidl_mlme::ControlledPortState::Open)
1800 .expect("expected OK");
1801 }
1802
1803 bss.handle_data_frame(
1804 &mut ctx,
1805 mac::DataFrame {
1806 fixed_fields: mac::FixedDataHdrFields {
1807 frame_ctrl: mac::FrameControl(0)
1808 .with_frame_type(mac::FrameType::DATA)
1809 .with_to_ds(true),
1810 duration: 0,
1811 addr1: (*BSSID).into(),
1812 addr2: *CLIENT_ADDR,
1813 addr3: *CLIENT_ADDR2,
1814 seq_ctrl: mac::SequenceControl(10),
1815 }
1816 .as_bytes_ref(),
1817 addr4: None,
1818 qos_ctrl: None,
1819 ht_ctrl: None,
1820 body: &[
1821 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1826 ][..],
1827 },
1828 )
1829 .expect("expected OK");
1830
1831 if controlled_port_open {
1832 assert_eq!(fake_device_state.lock().eth_queue.len(), 1);
1833 } else {
1834 assert!(fake_device_state.lock().eth_queue.is_empty());
1835 }
1836 }
1837
1838 async fn authenticate_client(
1839 fake_device_state: Arc<Mutex<FakeDeviceState>>,
1840 ctx: &mut Context<FakeDevice>,
1841 bss: &mut InfraBss,
1842 client_addr: MacAddr,
1843 ) {
1844 bss.handle_mgmt_frame(
1845 ctx,
1846 mac::MgmtFrame {
1847 mgmt_hdr: mac::MgmtHdr {
1848 frame_ctrl: mac::FrameControl(0)
1849 .with_frame_type(mac::FrameType::MGMT)
1850 .with_mgmt_subtype(mac::MgmtSubtype::AUTH),
1851 duration: 0,
1852 addr1: (*BSSID).into(),
1853 addr2: client_addr,
1854 addr3: (*BSSID).into(),
1855 seq_ctrl: mac::SequenceControl(10),
1856 }
1857 .as_bytes_ref(),
1858 ht_ctrl: None,
1859 body: &[
1860 0, 0, 1, 0, 0, 0, ][..],
1865 },
1866 )
1867 .await
1868 .expect("failed to handle auth req frame");
1869
1870 fake_device_state
1871 .lock()
1872 .next_mlme_msg::<fidl_mlme::AuthenticateIndication>()
1873 .expect("expected auth indication");
1874 bss.handle_mlme_auth_resp(
1875 ctx,
1876 fidl_mlme::AuthenticateResponse {
1877 peer_sta_address: client_addr.to_array(),
1878 result_code: fidl_mlme::AuthenticateResultCode::Success,
1879 },
1880 )
1881 .await
1882 .expect("failed to handle auth resp");
1883 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1884 fake_device_state.lock().wlan_queue.clear();
1885 }
1886
1887 async fn associate_client(
1888 fake_device_state: Arc<Mutex<FakeDeviceState>>,
1889 ctx: &mut Context<FakeDevice>,
1890 bss: &mut InfraBss,
1891 client_addr: MacAddr,
1892 association_id: u16,
1893 ) {
1894 bss.handle_mgmt_frame(
1895 ctx,
1896 mac::MgmtFrame {
1897 mgmt_hdr: mac::MgmtHdr {
1898 frame_ctrl: mac::FrameControl(0)
1899 .with_frame_type(mac::FrameType::MGMT)
1900 .with_mgmt_subtype(mac::MgmtSubtype::ASSOC_REQ),
1901 duration: 0,
1902 addr1: (*BSSID).into(),
1903 addr2: client_addr,
1904 addr3: (*BSSID).into(),
1905 seq_ctrl: mac::SequenceControl(10),
1906 }
1907 .as_bytes_ref(),
1908 ht_ctrl: None,
1909 body: &[
1910 0, 0, 10, 0, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 2, 9, 10, 48, 2, 77, 88, ][..],
1918 },
1919 )
1920 .await
1921 .expect("expected OK");
1922 let msg = fake_device_state
1923 .lock()
1924 .next_mlme_msg::<fidl_mlme::AssociateIndication>()
1925 .expect("expected assoc indication");
1926 bss.handle_mlme_assoc_resp(
1927 ctx,
1928 fidl_mlme::AssociateResponse {
1929 peer_sta_address: client_addr.to_array(),
1930 result_code: fidl_mlme::AssociateResultCode::Success,
1931 association_id,
1932 capability_info: msg.capability_info,
1933 rates: msg.rates,
1934 },
1935 )
1936 .await
1937 .expect("failed to handle assoc resp");
1938 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1939 fake_device_state.lock().wlan_queue.clear();
1940 }
1941
1942 fn send_eth_frame_from_ds_to_client(
1943 ctx: &mut Context<FakeDevice>,
1944 bss: &mut InfraBss,
1945 client_addr: MacAddr,
1946 ) {
1947 bss.handle_eth_frame(
1948 ctx,
1949 EthernetIIHdr {
1950 da: client_addr,
1951 sa: *REMOTE_ADDR,
1952 ether_type: BigEndianU16::new(0x1234),
1953 },
1954 &[1, 2, 3, 4, 5][..],
1955 0.into(),
1956 )
1957 .expect("expected OK");
1958 }
1959
1960 #[fuchsia::test(allow_stalls = false)]
1961 async fn handle_multiple_complete_associations() {
1962 let (fake_device, fake_device_state) = FakeDevice::new().await;
1963 let (mut ctx, _) = make_context(fake_device);
1964 let mut bss = make_infra_bss(&mut ctx).await;
1965
1966 authenticate_client(fake_device_state.clone(), &mut ctx, &mut bss, *CLIENT_ADDR).await;
1967 authenticate_client(fake_device_state.clone(), &mut ctx, &mut bss, *CLIENT_ADDR2).await;
1968
1969 associate_client(fake_device_state.clone(), &mut ctx, &mut bss, *CLIENT_ADDR, 1).await;
1970 associate_client(fake_device_state.clone(), &mut ctx, &mut bss, *CLIENT_ADDR2, 2).await;
1971
1972 assert!(bss.clients.contains_key(&CLIENT_ADDR));
1973 assert!(bss.clients.contains_key(&CLIENT_ADDR2));
1974
1975 send_eth_frame_from_ds_to_client(&mut ctx, &mut bss, *CLIENT_ADDR);
1976 send_eth_frame_from_ds_to_client(&mut ctx, &mut bss, *CLIENT_ADDR2);
1977
1978 assert_eq!(fake_device_state.lock().wlan_queue.len(), 2);
1979 }
1980
1981 #[fuchsia::test(allow_stalls = false)]
1982 async fn handle_ps_poll() {
1983 let (fake_device, fake_device_state) = FakeDevice::new().await;
1984 let (mut ctx, _) = make_context(fake_device);
1985 let mut bss = make_infra_bss(&mut ctx).await;
1986 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1987
1988 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1989 client
1990 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1991 .await
1992 .expect("expected OK");
1993 client
1994 .handle_mlme_assoc_resp(
1995 &mut ctx,
1996 false,
1997 1,
1998 mac::CapabilityInfo(0),
1999 fidl_mlme::AssociateResultCode::Success,
2000 1,
2001 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
2002 )
2003 .await
2004 .expect("expected OK");
2005 client.set_power_state(&mut ctx, mac::PowerState::DOZE).expect("expected doze ok");
2006 fake_device_state.lock().wlan_queue.clear();
2007
2008 bss.handle_eth_frame(
2009 &mut ctx,
2010 EthernetIIHdr {
2011 da: *CLIENT_ADDR,
2012 sa: *CLIENT_ADDR2,
2013 ether_type: BigEndianU16::new(0x1234),
2014 },
2015 &[1, 2, 3, 4, 5][..],
2016 0.into(),
2017 )
2018 .expect("expected OK");
2019 assert_eq!(fake_device_state.lock().wlan_queue.len(), 0);
2020
2021 bss.handle_ctrl_frame(
2022 &mut ctx,
2023 mac::CtrlFrame {
2024 frame_ctrl: mac::FrameControl(0)
2025 .with_frame_type(mac::FrameType::CTRL)
2026 .with_ctrl_subtype(mac::CtrlSubtype::PS_POLL),
2027 body: &[
2028 0b00000001, 0b11000000, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, ][..],
2032 },
2033 )
2034 .expect("expected OK");
2035 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
2036 assert_eq!(
2037 &fake_device_state.lock().wlan_queue[0].0[..],
2038 &[
2039 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,
2051 ][..]
2052 );
2053 }
2054
2055 #[fuchsia::test(allow_stalls = false)]
2056 async fn handle_mlme_setkeys_req() {
2057 let (fake_device, fake_device_state) = FakeDevice::new().await;
2058 let (mut ctx, _) = make_context(fake_device);
2059 let mut bss = make_protected_infra_bss(&mut ctx).await;
2060 bss.handle_mlme_setkeys_req(
2061 &mut ctx,
2062 vec![fidl_mlme::SetKeyDescriptor {
2063 cipher_suite_oui: [1, 2, 3],
2064 cipher_suite_type: fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
2065 key_type: fidl_mlme::KeyType::Pairwise,
2066 address: [5; 6].into(),
2067 key_id: 6,
2068 key: vec![1, 2, 3, 4, 5, 6, 7],
2069 rsc: 8,
2070 }],
2071 )
2072 .await
2073 .expect("expected InfraBss::handle_mlme_setkeys_req OK");
2074 assert_eq!(
2075 fake_device_state.lock().keys,
2076 vec![fidl_softmac::WlanKeyConfiguration {
2077 protection: Some(fidl_softmac::WlanProtection::RxTx),
2078 cipher_oui: Some([1, 2, 3]),
2079 cipher_type: Some(4),
2080 key_type: Some(fidl_ieee80211::KeyType::Pairwise),
2081 peer_addr: Some([5; 6]),
2082 key_idx: Some(6),
2083 key: Some(vec![1, 2, 3, 4, 5, 6, 7]),
2084 rsc: Some(8),
2085 ..Default::default()
2086 }]
2087 );
2088 }
2089
2090 #[fuchsia::test(allow_stalls = false)]
2091 async fn handle_mlme_setkeys_req_no_rsne() {
2092 let (fake_device, fake_device_state) = FakeDevice::new().await;
2093 let (mut ctx, _) = make_context(fake_device);
2094 let mut bss = make_infra_bss(&mut ctx).await;
2095 assert_matches!(
2096 bss.handle_mlme_setkeys_req(
2097 &mut ctx,
2098 vec![fidl_mlme::SetKeyDescriptor {
2099 cipher_suite_oui: [1, 2, 3],
2100 cipher_suite_type:
2101 fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
2102 key_type: fidl_mlme::KeyType::Pairwise,
2103 address: [5; 6],
2104 key_id: 6,
2105 key: vec![1, 2, 3, 4, 5, 6, 7],
2106 rsc: 8,
2107 }]
2108 )
2109 .await
2110 .expect_err("expected InfraBss::handle_mlme_setkeys_req error"),
2111 Error::Status(_, zx::Status::BAD_STATE)
2112 );
2113 assert!(fake_device_state.lock().keys.is_empty());
2114 }
2115
2116 #[fuchsia::test(allow_stalls = false)]
2117 async fn handle_probe_req() {
2118 let (fake_device, fake_device_state) = FakeDevice::new().await;
2119 let (mut ctx, _) = make_context(fake_device);
2120 let mut bss = InfraBss::new(
2121 &mut ctx,
2122 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2123 TimeUnit::DEFAULT_BEACON_INTERVAL,
2124 2,
2125 mac::CapabilityInfo(33),
2126 vec![248],
2127 1,
2128 Some(vec![48, 2, 77, 88]),
2129 )
2130 .await
2131 .expect("expected InfraBss::new ok");
2132
2133 bss.handle_probe_req(&mut ctx, *CLIENT_ADDR)
2134 .expect("expected InfraBss::handle_probe_req ok");
2135 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
2136 assert_eq!(
2137 &fake_device_state.lock().wlan_queue[0].0[..],
2138 &[
2139 0b01010000, 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, 0, 0, 0, 0, 100, 0, 33, 0, 0, 5, 1, 2, 3, 4, 5, 1, 1, 248, 3, 1, 1, 48, 2, 77, 88, ][..]
2156 );
2157 }
2158
2159 #[fuchsia::test(allow_stalls = false)]
2160 async fn handle_probe_req_has_offload() {
2161 let (fake_device, _fake_device_state) = FakeDevice::new_with_config(
2162 FakeDeviceConfig::default().with_mock_probe_response_offload(
2163 fidl_softmac::ProbeResponseOffloadExtension { supported: true },
2164 ),
2165 )
2166 .await;
2167
2168 let (mut ctx, _) = make_context(fake_device);
2169 let mut bss = InfraBss::new(
2170 &mut ctx,
2171 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2172 TimeUnit::DEFAULT_BEACON_INTERVAL,
2173 2,
2174 CapabilityInfo(33),
2175 vec![0b11111000],
2176 1,
2177 Some(vec![48, 2, 77, 88]),
2178 )
2179 .await
2180 .expect("expected InfraBss::new ok");
2181
2182 bss.handle_mgmt_frame(
2183 &mut ctx,
2184 mac::MgmtFrame {
2185 mgmt_hdr: mac::MgmtHdr {
2186 frame_ctrl: mac::FrameControl(0)
2187 .with_frame_type(mac::FrameType::MGMT)
2188 .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
2189 duration: 0,
2190 addr1: (*BSSID).into(),
2191 addr2: *CLIENT_ADDR,
2192 addr3: (*BSSID).into(),
2193 seq_ctrl: mac::SequenceControl(10),
2194 }
2195 .as_bytes_ref(),
2196 ht_ctrl: None,
2197 body: &[][..],
2198 },
2199 )
2200 .await
2201 .expect_err("expected InfraBss::handle_mgmt_frame error");
2202 }
2203
2204 #[fuchsia::test(allow_stalls = false)]
2205 async fn handle_probe_req_wildcard_ssid() {
2206 let (fake_device, fake_device_state) = FakeDevice::new().await;
2207 let (mut ctx, _) = make_context(fake_device);
2208 let mut bss = InfraBss::new(
2209 &mut ctx,
2210 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2211 TimeUnit::DEFAULT_BEACON_INTERVAL,
2212 2,
2213 CapabilityInfo(33),
2214 vec![0b11111000],
2215 1,
2216 Some(vec![48, 2, 77, 88]),
2217 )
2218 .await
2219 .expect("expected InfraBss::new ok");
2220
2221 bss.handle_mgmt_frame(
2222 &mut ctx,
2223 mac::MgmtFrame {
2224 mgmt_hdr: mac::MgmtHdr {
2225 frame_ctrl: mac::FrameControl(0)
2226 .with_frame_type(mac::FrameType::MGMT)
2227 .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
2228 duration: 0,
2229 addr1: (*BSSID).into(),
2230 addr2: *CLIENT_ADDR,
2231 addr3: (*BSSID).into(),
2232 seq_ctrl: mac::SequenceControl(10),
2233 }
2234 .as_bytes_ref(),
2235 ht_ctrl: None,
2236 body: &[
2237 0, 0, ][..],
2239 },
2240 )
2241 .await
2242 .expect("expected InfraBss::handle_mgmt_frame ok");
2243
2244 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
2245 assert_eq!(
2246 &fake_device_state.lock().wlan_queue[0].0[..],
2247 &[
2248 0b01010000, 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, 0, 0, 0, 0, 100, 0, 33, 0, 0, 5, 1, 2, 3, 4, 5, 1, 1, 248, 3, 1, 1, 48, 2, 77, 88, ][..]
2265 );
2266 }
2267
2268 #[fuchsia::test(allow_stalls = false)]
2269 async fn handle_probe_req_matching_ssid() {
2270 let (fake_device, fake_device_state) = FakeDevice::new().await;
2271 let (mut ctx, _) = make_context(fake_device);
2272 let mut bss = InfraBss::new(
2273 &mut ctx,
2274 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2275 TimeUnit::DEFAULT_BEACON_INTERVAL,
2276 2,
2277 CapabilityInfo(33),
2278 vec![0b11111000],
2279 1,
2280 Some(vec![48, 2, 77, 88]),
2281 )
2282 .await
2283 .expect("expected InfraBss::new ok");
2284
2285 bss.handle_mgmt_frame(
2286 &mut ctx,
2287 mac::MgmtFrame {
2288 mgmt_hdr: mac::MgmtHdr {
2289 frame_ctrl: mac::FrameControl(0)
2290 .with_frame_type(mac::FrameType::MGMT)
2291 .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
2292 duration: 0,
2293 addr1: (*BSSID).into(),
2294 addr2: *CLIENT_ADDR,
2295 addr3: (*BSSID).into(),
2296 seq_ctrl: mac::SequenceControl(10),
2297 }
2298 .as_bytes_ref(),
2299 ht_ctrl: None,
2300 body: &[0, 5, 1, 2, 3, 4, 5][..],
2301 },
2302 )
2303 .await
2304 .expect("expected InfraBss::handle_mgmt_frame ok");
2305
2306 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
2307 assert_eq!(
2308 &fake_device_state.lock().wlan_queue[0].0[..],
2309 &[
2310 0b01010000, 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, 0, 0, 0, 0, 100, 0, 33, 0, 0, 5, 1, 2, 3, 4, 5, 1, 1, 248, 3, 1, 1, 48, 2, 77, 88, ][..]
2327 );
2328 }
2329
2330 #[fuchsia::test(allow_stalls = false)]
2331 async fn handle_probe_req_mismatching_ssid() {
2332 let (fake_device, _) = FakeDevice::new().await;
2333 let (mut ctx, _) = make_context(fake_device);
2334 let mut bss = InfraBss::new(
2335 &mut ctx,
2336 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2337 TimeUnit::DEFAULT_BEACON_INTERVAL,
2338 2,
2339 CapabilityInfo(33),
2340 vec![0b11111000],
2341 1,
2342 Some(vec![48, 2, 77, 88]),
2343 )
2344 .await
2345 .expect("expected InfraBss::new ok");
2346
2347 assert_matches!(
2348 bss.handle_mgmt_frame(
2349 &mut ctx,
2350 mac::MgmtFrame {
2351 mgmt_hdr: mac::MgmtHdr {
2352 frame_ctrl: mac::FrameControl(0)
2353 .with_frame_type(mac::FrameType::MGMT)
2354 .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
2355 duration: 0,
2356 addr1: (*BSSID).into(),
2357 addr2: *CLIENT_ADDR,
2358 addr3: (*BSSID).into(),
2359 seq_ctrl: mac::SequenceControl(10),
2360 }
2361 .as_bytes_ref(),
2362 ht_ctrl: None,
2363 body: &[0, 5, 1, 2, 3, 4, 6][..],
2364 },
2365 )
2366 .await
2367 .expect_err("expected InfraBss::handle_mgmt_frame error"),
2368 Rejection::OtherBss
2369 );
2370 }
2371
2372 #[fuchsia::test(allow_stalls = false)]
2373 async fn make_tim() {
2374 let (fake_device, _) = FakeDevice::new().await;
2375 let (mut ctx, _) = make_context(fake_device);
2376 let mut bss = make_infra_bss(&mut ctx).await;
2377 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
2378
2379 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
2380 client
2381 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
2382 .await
2383 .expect("expected OK");
2384 client
2385 .handle_mlme_assoc_resp(
2386 &mut ctx,
2387 false,
2388 1,
2389 mac::CapabilityInfo(0),
2390 fidl_mlme::AssociateResultCode::Success,
2391 1,
2392 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
2393 )
2394 .await
2395 .expect("expected OK");
2396 client.set_power_state(&mut ctx, mac::PowerState::DOZE).expect("expected doze OK");
2397
2398 bss.handle_eth_frame(
2399 &mut ctx,
2400 EthernetIIHdr {
2401 da: *CLIENT_ADDR,
2402 sa: *CLIENT_ADDR2,
2403 ether_type: BigEndianU16::new(0x1234),
2404 },
2405 &[1, 2, 3, 4, 5][..],
2406 0.into(),
2407 )
2408 .expect("expected OK");
2409
2410 let tim = bss.make_tim();
2411 let (pvb_offset, pvb_bitmap) = tim.make_partial_virtual_bitmap();
2412 assert_eq!(pvb_offset, 0);
2413 assert_eq!(pvb_bitmap, &[0b00000010][..]);
2414 }
2415
2416 #[fuchsia::test(allow_stalls = false)]
2417 async fn make_tim_empty() {
2418 let (fake_device, _) = FakeDevice::new().await;
2419 let (mut ctx, _) = make_context(fake_device);
2420 let bss = make_infra_bss(&mut ctx).await;
2421
2422 let tim = bss.make_tim();
2423 let (pvb_offset, pvb_bitmap) = tim.make_partial_virtual_bitmap();
2424 assert_eq!(pvb_offset, 0);
2425 assert_eq!(pvb_bitmap, &[0b00000000][..]);
2426 }
2427}