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 .and_then(|offload| offload.supported)
354 .unwrap_or(false)
355 {
356 return Err(Rejection::Error(format_err!(
358 "driver indicates probe response offload but MLME received a probe response!"
359 )));
360 }
361
362 if to_bss
363 || (mgmt_frame.mgmt_hdr.addr1 == ieee80211::BROADCAST_ADDR
364 && mgmt_frame.mgmt_hdr.addr3 == ieee80211::BROADCAST_ADDR)
365 {
366 for (id, ie_body) in mgmt_frame.into_ies().1 {
368 match id {
369 ie::Id::SSID => {
370 if !ie_body.is_empty() && *ie_body != self.ssid[..] {
371 return Err(Rejection::OtherBss);
373 }
374 }
375 _ => {}
376 }
377 }
378
379 return self.handle_probe_req(ctx, client_addr);
382 } else {
383 return Err(Rejection::OtherBss);
385 }
386 } else if !to_bss {
387 return Err(Rejection::OtherBss);
389 }
390
391 let mut new_client = None;
395 let client = match self.clients.get_mut(&client_addr) {
396 Some(client) => client,
397 None => new_client.get_or_insert_with(|| RemoteClient::new(client_addr)),
398 };
399
400 if let Err(e) = client
401 .handle_mgmt_frame(ctx, self.capabilities, Some(self.ssid.clone()), mgmt_frame)
402 .await
403 {
404 return Err(Rejection::Client(client_addr, e));
405 }
406
407 match client.set_power_state(ctx, frame_ctrl.power_mgmt()) {
410 Err(ClientRejection::NotAssociated) => {
411 error!("client {:02X?} tried to doze but is not associated", client_addr);
412 }
413 Err(e) => {
414 return Err(Rejection::Client(client.addr, e));
415 }
416 Ok(()) => {}
417 }
418
419 if client.deauthenticated() {
420 if new_client.is_none() {
421 self.clients.remove(&client_addr);
424 }
425 } else {
426 if let Some(client) = new_client.take() {
428 self.clients.insert(client_addr, client);
429 }
430 }
431
432 Ok(())
433 }
434
435 pub fn handle_data_frame<B: SplitByteSlice, D: DeviceOps>(
439 &mut self,
440 ctx: &mut Context<D>,
441 data_frame: mac::DataFrame<B>,
442 ) -> Result<(), Rejection> {
443 if mac::data_receiver_addr(&data_frame.fixed_fields).as_array() != ctx.bssid.as_array() {
444 return Err(Rejection::OtherBss);
446 }
447
448 let frame_ctrl = data_frame.frame_ctrl();
449 if !*&frame_ctrl.to_ds() || *&frame_ctrl.from_ds() {
450 return Err(Rejection::BadDsBits);
453 }
454
455 let src_addr =
456 mac::data_src_addr(&data_frame.fixed_fields, data_frame.addr4.as_deref().copied())
457 .ok_or(Rejection::NoSrcAddr)?;
458
459 let mut maybe_client = None;
462 let client = self
463 .clients
464 .get_mut(&src_addr)
465 .unwrap_or_else(|| maybe_client.get_or_insert_with(|| RemoteClient::new(src_addr)));
466
467 client.handle_data_frame(ctx, data_frame).map_err(|e| Rejection::Client(client.addr, e))?;
468
469 match client.set_power_state(ctx, frame_ctrl.power_mgmt()) {
472 Err(ClientRejection::NotAssociated) => {
473 error!("client {:02X?} tried to doze but is not associated", client.addr);
474 }
475 Err(e) => {
476 return Err(Rejection::Client(client.addr, e));
477 }
478 Ok(()) => {}
479 }
480
481 Ok(())
482 }
483
484 pub fn handle_ctrl_frame<B: SplitByteSlice, D: DeviceOps>(
485 &mut self,
486 ctx: &mut Context<D>,
487 ctrl_frame: mac::CtrlFrame<B>,
488 ) -> Result<(), Rejection> {
489 match ctrl_frame.try_into_ctrl_body().ok_or(Rejection::FrameMalformed)? {
490 mac::CtrlBody::PsPoll { ps_poll } => {
491 let client = match self.clients.get_mut(&ps_poll.ta) {
492 Some(client) => client,
493 _ => {
494 return Err(Rejection::Client(
495 ps_poll.ta,
496 ClientRejection::NotAuthenticated,
497 ));
498 }
499 };
500
501 const PS_POLL_MASK: u16 = 0b11000000_00000000;
504 client
505 .handle_ps_poll(ctx, ps_poll.masked_aid & !PS_POLL_MASK)
506 .map_err(|e| Rejection::Client(client.addr, e))
507 }
508 _ => Err(Rejection::FrameMalformed),
509 }
510 }
511
512 pub fn handle_multicast_eth_frame<D: DeviceOps>(
513 &mut self,
514 ctx: &mut Context<D>,
515 hdr: EthernetIIHdr,
516 body: &[u8],
517 async_id: trace::Id,
518 ) -> Result<(), Rejection> {
519 let buffer = ctx
520 .make_data_frame(
521 hdr.da,
522 hdr.sa,
523 self.rsne.is_some(),
524 false, hdr.ether_type.get(),
526 body,
527 )
528 .map_err(|e| Rejection::Client(hdr.da, ClientRejection::WlanSendError(e)))?;
529 let tx_flags = fidl_softmac::WlanTxInfoFlags::empty();
530
531 if !self.clients.values().any(|client| client.dozing()) {
532 ctx.device.send_wlan_frame(buffer, tx_flags, Some(async_id)).map_err(move |s| {
533 Rejection::Client(
534 hdr.da,
535 ClientRejection::WlanSendError(Error::Status(
536 format!("error sending multicast data frame"),
537 s,
538 )),
539 )
540 })?;
541 } else {
542 self.group_buffered.push_back(BufferedFrame { buffer, tx_flags, async_id });
543 }
544
545 Ok(())
546 }
547
548 pub fn handle_eth_frame<D: DeviceOps>(
549 &mut self,
550 ctx: &mut Context<D>,
551 hdr: EthernetIIHdr,
552 body: &[u8],
553 async_id: trace::Id,
554 ) -> Result<(), Rejection> {
555 if hdr.da.is_multicast() {
556 return self.handle_multicast_eth_frame(ctx, hdr, body, async_id);
557 }
558
559 let mut maybe_client = None;
562 let client = self
563 .clients
564 .get_mut(&hdr.da)
565 .unwrap_or_else(|| maybe_client.get_or_insert_with(|| RemoteClient::new(hdr.da)));
566 client
567 .handle_eth_frame(ctx, hdr.da, hdr.sa, hdr.ether_type.get(), body, async_id)
568 .map_err(|e| Rejection::Client(client.addr, e))
569 }
570
571 #[allow(dead_code)]
573 pub fn handle_bcn_tx_complete_indication<D: DeviceOps>(
574 &mut self,
575 ctx: &mut Context<D>,
576 ) -> Result<(), Error> {
577 if self.dtim_count > 0 {
578 self.dtim_count -= 1;
579 return Ok(());
580 }
581
582 self.dtim_count = self.dtim_period;
583
584 let mut buffered = self.group_buffered.drain(..).peekable();
585 while let Some(BufferedFrame { mut buffer, tx_flags, async_id }) = buffered.next() {
586 if buffered.peek().is_some() {
587 frame_writer::set_more_data(&mut buffer[..])?;
588 }
589 ctx.device
590 .send_wlan_frame(buffer, tx_flags, Some(async_id))
591 .map_err(|s| Error::Status(format!("error sending buffered frame"), s))?;
592 }
593
594 Ok(())
595 }
596
597 pub async fn handle_timed_event<D: DeviceOps>(
601 &mut self,
602 ctx: &mut Context<D>,
603 event: TimedEvent,
604 ) -> Result<(), Rejection> {
605 match event {
606 TimedEvent::ClientEvent(addr, event) => {
607 let client = self.clients.get_mut(&addr).ok_or(Rejection::NoSuchClient(addr))?;
608 client.handle_event(ctx, event).await.map_err(|e| Rejection::Client(client.addr, e))
609 }
610 }
611 }
612}
613
614#[cfg(test)]
615mod tests {
616 use super::*;
617 use crate::ap::remote_client::ClientEvent;
618 use crate::device::{FakeDevice, FakeDeviceConfig, FakeDeviceState};
619 use assert_matches::assert_matches;
620 use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
621 use fuchsia_sync::Mutex;
622 use ieee80211::Bssid;
623 use std::sync::{Arc, LazyLock};
624 use test_case::test_case;
625 use wlan_common::mac::IntoBytesExt as _;
626 use wlan_common::test_utils::fake_frames::fake_wpa2_rsne;
627 use wlan_common::timer::{self, create_timer};
628 use zerocopy::byteorder::big_endian::U16 as BigEndianU16;
629
630 static CLIENT_ADDR: LazyLock<MacAddr> = LazyLock::new(|| [4u8; 6].into());
631 static BSSID: LazyLock<Bssid> = LazyLock::new(|| [2u8; 6].into());
632 static CLIENT_ADDR2: LazyLock<MacAddr> = LazyLock::new(|| [6u8; 6].into());
633 static REMOTE_ADDR: LazyLock<MacAddr> = LazyLock::new(|| [123u8; 6].into());
634
635 fn make_context(
636 fake_device: FakeDevice,
637 ) -> (Context<FakeDevice>, timer::EventStream<TimedEvent>) {
638 let (timer, time_stream) = create_timer();
639 (Context::new(fake_device, timer, *BSSID), time_stream)
640 }
641
642 async fn make_infra_bss(ctx: &mut Context<FakeDevice>) -> InfraBss {
643 InfraBss::new(
644 ctx,
645 Ssid::try_from("coolnet").unwrap(),
646 TimeUnit::DEFAULT_BEACON_INTERVAL,
647 2,
648 CapabilityInfo(0),
649 vec![0b11111000],
650 1,
651 None,
652 )
653 .await
654 .expect("expected InfraBss::new ok")
655 }
656
657 async fn make_protected_infra_bss(ctx: &mut Context<FakeDevice>) -> InfraBss {
658 InfraBss::new(
659 ctx,
660 Ssid::try_from("coolnet").unwrap(),
661 TimeUnit::DEFAULT_BEACON_INTERVAL,
662 2,
663 CapabilityInfo(0),
664 vec![0b11111000],
665 1,
666 Some(fake_wpa2_rsne()),
667 )
668 .await
669 .expect("expected InfraBss::new ok")
670 }
671
672 #[fuchsia::test(allow_stalls = false)]
673 async fn new() {
674 let (fake_device, fake_device_state) = FakeDevice::new().await;
675 let (mut ctx, _) = make_context(fake_device);
676 InfraBss::new(
677 &mut ctx,
678 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
679 TimeUnit::DEFAULT_BEACON_INTERVAL,
680 2,
681 CapabilityInfo(0).with_ess(true),
682 vec![0b11111000],
683 1,
684 None,
685 )
686 .await
687 .expect("expected InfraBss::new ok");
688
689 assert_eq!(
690 fake_device_state.lock().wlan_channel,
691 fidl_ieee80211::WlanChannel {
692 primary: 1,
693 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
694 secondary80: 0
695 }
696 );
697
698 let beacon_tmpl = vec![
699 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, ];
716
717 assert_eq!(
718 fake_device_state.lock().beacon_config.as_ref().expect("expected beacon_config"),
719 &(beacon_tmpl, 49, TimeUnit::DEFAULT_BEACON_INTERVAL)
720 );
721 }
722
723 #[fuchsia::test(allow_stalls = false)]
724 async fn stop() {
725 let (fake_device, fake_device_state) = FakeDevice::new().await;
726 let (mut ctx, _) = make_context(fake_device);
727 let bss = make_infra_bss(&mut ctx).await;
728 bss.stop(&mut ctx).await.expect("expected InfraBss::stop ok");
729 assert!(fake_device_state.lock().beacon_config.is_none());
730 }
731
732 #[fuchsia::test(allow_stalls = false)]
733 async fn handle_mlme_auth_resp() {
734 let (fake_device, fake_device_state) = FakeDevice::new().await;
735 let (mut ctx, _) = make_context(fake_device);
736 let mut bss = make_infra_bss(&mut ctx).await;
737
738 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
739
740 bss.handle_mlme_auth_resp(
741 &mut ctx,
742 fidl_mlme::AuthenticateResponse {
743 peer_sta_address: CLIENT_ADDR.to_array(),
744 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
745 },
746 )
747 .await
748 .expect("expected InfraBss::handle_mlme_auth_resp ok");
749 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
750 assert_eq!(
751 &fake_device_state.lock().wlan_queue[0].0[..],
752 &[
753 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, ][..]
765 );
766 }
767
768 #[fuchsia::test(allow_stalls = false)]
769 async fn handle_mlme_auth_resp_no_such_client() {
770 let (fake_device, _) = FakeDevice::new().await;
771 let (mut ctx, _) = make_context(fake_device);
772 let mut bss = make_infra_bss(&mut ctx).await;
773
774 assert_eq!(
775 zx::Status::from(
776 bss.handle_mlme_auth_resp(
777 &mut ctx,
778 fidl_mlme::AuthenticateResponse {
779 peer_sta_address: CLIENT_ADDR.to_array(),
780 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
781 },
782 )
783 .await
784 .expect_err("expected InfraBss::handle_mlme_auth_resp error")
785 ),
786 zx::Status::NOT_FOUND
787 );
788 }
789
790 #[fuchsia::test(allow_stalls = false)]
791 async fn handle_mlme_deauth_req() {
792 let (fake_device, fake_device_state) = FakeDevice::new().await;
793 let (mut ctx, _) = make_context(fake_device);
794 let mut bss = make_infra_bss(&mut ctx).await;
795
796 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
797
798 bss.handle_mlme_deauth_req(
799 &mut ctx,
800 fidl_mlme::DeauthenticateRequest {
801 peer_sta_address: CLIENT_ADDR.to_array(),
802 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
803 },
804 )
805 .await
806 .expect("expected InfraBss::handle_mlme_deauth_req ok");
807 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
808 assert_eq!(
809 &fake_device_state.lock().wlan_queue[0].0[..],
810 &[
811 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, ][..]
821 );
822
823 assert!(!bss.clients.contains_key(&CLIENT_ADDR));
824 }
825
826 #[fuchsia::test(allow_stalls = false)]
827 async fn handle_mlme_assoc_resp() {
828 let (fake_device, fake_device_state) = FakeDevice::new().await;
829 let (mut ctx, _) = make_context(fake_device);
830 let mut bss = make_infra_bss(&mut ctx).await;
831
832 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
833 bss.handle_mlme_assoc_resp(
834 &mut ctx,
835 fidl_mlme::AssociateResponse {
836 peer_sta_address: CLIENT_ADDR.to_array(),
837 result_code: fidl_mlme::AssociateResultCode::Success,
838 association_id: 1,
839 capability_info: 0,
840 rates: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
841 },
842 )
843 .await
844 .expect("expected InfraBss::handle_mlme_assoc_resp ok");
845 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
846 assert_eq!(
847 &fake_device_state.lock().wlan_queue[0].0[..],
848 &[
849 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, ][..]
865 );
866 assert!(fake_device_state.lock().assocs.contains_key(&CLIENT_ADDR));
867 }
868
869 #[fuchsia::test(allow_stalls = false)]
870 async fn handle_mlme_assoc_resp_with_caps() {
871 let (fake_device, fake_device_state) = FakeDevice::new().await;
872 let (mut ctx, _) = make_context(fake_device);
873 let mut bss = InfraBss::new(
874 &mut ctx,
875 Ssid::try_from("coolnet").unwrap(),
876 TimeUnit::DEFAULT_BEACON_INTERVAL,
877 2,
878 CapabilityInfo(0).with_short_preamble(true).with_ess(true),
879 vec![0b11111000],
880 1,
881 None,
882 )
883 .await
884 .expect("expected InfraBss::new ok");
885
886 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
887
888 bss.handle_mlme_assoc_resp(
889 &mut ctx,
890 fidl_mlme::AssociateResponse {
891 peer_sta_address: CLIENT_ADDR.to_array(),
892 result_code: fidl_mlme::AssociateResultCode::Success,
893 association_id: 1,
894 capability_info: CapabilityInfo(0).with_short_preamble(true).raw(),
895 rates: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
896 },
897 )
898 .await
899 .expect("expected InfraBss::handle_mlme_assoc_resp ok");
900 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
901 assert_eq!(
902 &fake_device_state.lock().wlan_queue[0].0[..],
903 &[
904 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, ][..]
920 );
921 assert!(fake_device_state.lock().assocs.contains_key(&CLIENT_ADDR));
922 }
923
924 #[fuchsia::test(allow_stalls = false)]
925 async fn handle_mlme_disassoc_req() {
926 let (fake_device, fake_device_state) = FakeDevice::new().await;
927 let (mut ctx, _) = make_context(fake_device);
928 let mut bss = make_infra_bss(&mut ctx).await;
929
930 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
931
932 bss.handle_mlme_disassoc_req(
933 &mut ctx,
934 fidl_mlme::DisassociateRequest {
935 peer_sta_address: CLIENT_ADDR.to_array(),
936 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDisassoc,
937 },
938 )
939 .await
940 .expect("expected InfraBss::handle_mlme_disassoc_req ok");
941 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
942 assert_eq!(
943 &fake_device_state.lock().wlan_queue[0].0[..],
944 &[
945 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, ][..]
955 );
956 }
957
958 #[fuchsia::test(allow_stalls = false)]
959 async fn handle_mlme_set_controlled_port_req() {
960 let (fake_device, _) = FakeDevice::new().await;
961 let (mut ctx, _) = make_context(fake_device);
962 let mut bss = make_protected_infra_bss(&mut ctx).await;
963
964 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
965
966 bss.handle_mlme_assoc_resp(
967 &mut ctx,
968 fidl_mlme::AssociateResponse {
969 peer_sta_address: CLIENT_ADDR.to_array(),
970 result_code: fidl_mlme::AssociateResultCode::Success,
971 association_id: 1,
972 capability_info: 0,
973 rates: vec![1, 2, 3],
974 },
975 )
976 .await
977 .expect("expected InfraBss::handle_mlme_assoc_resp ok");
978
979 bss.handle_mlme_set_controlled_port_req(fidl_mlme::SetControlledPortRequest {
980 peer_sta_address: CLIENT_ADDR.to_array(),
981 state: fidl_mlme::ControlledPortState::Open,
982 })
983 .expect("expected InfraBss::handle_mlme_set_controlled_port_req ok");
984 }
985
986 #[fuchsia::test(allow_stalls = false)]
987 async fn handle_mlme_eapol_req() {
988 let (fake_device, fake_device_state) = FakeDevice::new().await;
989 let (mut ctx, _) = make_context(fake_device);
990 let mut bss = make_infra_bss(&mut ctx).await;
991
992 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
993
994 bss.handle_mlme_eapol_req(
995 &mut ctx,
996 fidl_mlme::EapolRequest {
997 dst_addr: CLIENT_ADDR.to_array(),
998 src_addr: BSSID.to_array(),
999 data: vec![1, 2, 3],
1000 },
1001 )
1002 .expect("expected InfraBss::handle_mlme_eapol_req ok");
1003 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1004 assert_eq!(
1005 &fake_device_state.lock().wlan_queue[0].0[..],
1006 &[
1007 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,
1019 ][..]
1020 );
1021
1022 let confirm = fake_device_state
1023 .lock()
1024 .next_mlme_msg::<fidl_mlme::EapolConfirm>()
1025 .expect("Did not receive valid Eapol Confirm msg");
1026 assert_eq!(confirm.result_code, fidl_mlme::EapolResultCode::Success);
1027 assert_eq!(&confirm.dst_addr, CLIENT_ADDR.as_array());
1028 }
1029
1030 #[fuchsia::test(allow_stalls = false)]
1031 async fn handle_mgmt_frame_auth() {
1032 let (fake_device, fake_device_state) = FakeDevice::new().await;
1033 let (mut ctx, _) = make_context(fake_device);
1034 let mut bss = make_infra_bss(&mut ctx).await;
1035
1036 bss.handle_mgmt_frame(
1037 &mut ctx,
1038 mac::MgmtFrame {
1039 mgmt_hdr: mac::MgmtHdr {
1040 frame_ctrl: mac::FrameControl(0)
1041 .with_frame_type(mac::FrameType::MGMT)
1042 .with_mgmt_subtype(mac::MgmtSubtype::AUTH),
1043 duration: 0,
1044 addr1: (*BSSID).into(),
1045 addr2: *CLIENT_ADDR,
1046 addr3: (*BSSID).into(),
1047 seq_ctrl: mac::SequenceControl(10),
1048 }
1049 .as_bytes_ref(),
1050 ht_ctrl: None,
1051 body: &[
1052 0, 0, 1, 0, 0, 0, ][..],
1057 },
1058 )
1059 .await
1060 .expect("expected OK");
1061
1062 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), true);
1063
1064 let msg = fake_device_state
1065 .lock()
1066 .next_mlme_msg::<fidl_mlme::AuthenticateIndication>()
1067 .expect("expected MLME message");
1068 assert_eq!(
1069 msg,
1070 fidl_mlme::AuthenticateIndication {
1071 peer_sta_address: CLIENT_ADDR.to_array(),
1072 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1073 },
1074 );
1075 }
1076
1077 #[fuchsia::test(allow_stalls = false)]
1078 async fn handle_mgmt_frame_assoc_req() {
1079 let (fake_device, fake_device_state) = FakeDevice::new().await;
1080 let (mut ctx, _) = make_context(fake_device);
1081 let mut bss = make_infra_bss(&mut ctx).await;
1082
1083 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1084 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1085 client
1086 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1087 .await
1088 .expect("expected OK");
1089
1090 bss.handle_mgmt_frame(
1091 &mut ctx,
1092 mac::MgmtFrame {
1093 mgmt_hdr: mac::MgmtHdr {
1094 frame_ctrl: mac::FrameControl(0)
1095 .with_frame_type(mac::FrameType::MGMT)
1096 .with_mgmt_subtype(mac::MgmtSubtype::ASSOC_REQ),
1097 duration: 0,
1098 addr1: (*BSSID).into(),
1099 addr2: *CLIENT_ADDR,
1100 addr3: (*BSSID).into(),
1101 seq_ctrl: mac::SequenceControl(10),
1102 }
1103 .as_bytes_ref(),
1104 ht_ctrl: None,
1105 body: &[
1106 0, 0, 10, 0, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 2, 9, 10, 48, 2, 77, 88, ][..],
1114 },
1115 )
1116 .await
1117 .expect("expected OK");
1118
1119 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), true);
1120
1121 let msg = fake_device_state
1122 .lock()
1123 .next_mlme_msg::<fidl_mlme::AssociateIndication>()
1124 .expect("expected MLME message");
1125 assert_eq!(
1126 msg,
1127 fidl_mlme::AssociateIndication {
1128 peer_sta_address: CLIENT_ADDR.to_array(),
1129 listen_interval: 10,
1130 ssid: Some(Ssid::try_from("coolnet").unwrap().into()),
1131 capability_info: 0,
1132 rates: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
1133 rsne: Some(vec![48, 2, 77, 88]),
1134 },
1135 );
1136 }
1137
1138 #[fuchsia::test(allow_stalls = false)]
1139 async fn handle_mgmt_frame_bad_ds_bits_to_ds() {
1140 let (fake_device, _) = FakeDevice::new().await;
1141 let (mut ctx, _) = make_context(fake_device);
1142 let mut bss = make_infra_bss(&mut ctx).await;
1143
1144 assert_matches!(
1145 bss.handle_mgmt_frame(
1146 &mut ctx,
1147 mac::MgmtFrame {
1148 mgmt_hdr: mac::MgmtHdr {
1149 frame_ctrl: mac::FrameControl(0)
1150 .with_frame_type(mac::FrameType::MGMT)
1151 .with_mgmt_subtype(mac::MgmtSubtype::AUTH)
1152 .with_to_ds(true),
1153 duration: 0,
1154 addr1: (*BSSID).into(),
1155 addr2: *CLIENT_ADDR,
1156 addr3: (*BSSID).into(),
1157 seq_ctrl: mac::SequenceControl(10),
1158 }
1159 .as_bytes_ref(),
1160 ht_ctrl: None,
1161 body: &[
1162 0, 0, 1, 0, 0, 0, ][..],
1167 },
1168 )
1169 .await
1170 .expect_err("expected error"),
1171 Rejection::BadDsBits
1172 );
1173
1174 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), false);
1175 }
1176
1177 #[fuchsia::test(allow_stalls = false)]
1178 async fn handle_mgmt_frame_bad_ds_bits_from_ds() {
1179 let (fake_device, _) = FakeDevice::new().await;
1180 let (mut ctx, _) = make_context(fake_device);
1181 let mut bss = make_infra_bss(&mut ctx).await;
1182
1183 assert_matches!(
1184 bss.handle_mgmt_frame(
1185 &mut ctx,
1186 mac::MgmtFrame {
1187 mgmt_hdr: mac::MgmtHdr {
1188 frame_ctrl: mac::FrameControl(0)
1189 .with_frame_type(mac::FrameType::MGMT)
1190 .with_mgmt_subtype(mac::MgmtSubtype::AUTH)
1191 .with_from_ds(true),
1192 duration: 0,
1193 addr1: (*BSSID).into(),
1194 addr2: *CLIENT_ADDR,
1195 addr3: (*BSSID).into(),
1196 seq_ctrl: mac::SequenceControl(10),
1197 }
1198 .as_bytes_ref(),
1199 ht_ctrl: None,
1200 body: &[
1201 0, 0, 1, 0, 0, 0, ][..],
1206 },
1207 )
1208 .await
1209 .expect_err("expected error"),
1210 Rejection::BadDsBits
1211 );
1212
1213 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), false);
1214 }
1215
1216 #[fuchsia::test(allow_stalls = false)]
1217 async fn handle_mgmt_frame_no_such_client() {
1218 let (fake_device, _) = FakeDevice::new().await;
1219 let (mut ctx, _) = make_context(fake_device);
1220 let mut bss = make_infra_bss(&mut ctx).await;
1221
1222 assert_matches!(
1223 bss.handle_mgmt_frame(
1224 &mut ctx,
1225 mac::MgmtFrame {
1226 mgmt_hdr: mac::MgmtHdr {
1227 frame_ctrl: mac::FrameControl(0)
1228 .with_frame_type(mac::FrameType::MGMT)
1229 .with_mgmt_subtype(mac::MgmtSubtype::DISASSOC),
1230 duration: 0,
1231 addr1: (*BSSID).into(),
1232 addr2: *CLIENT_ADDR,
1233 addr3: (*BSSID).into(),
1234 seq_ctrl: mac::SequenceControl(10),
1235 }
1236 .as_bytes_ref(),
1237 ht_ctrl: None,
1238 body: &[
1239 8, 0, ][..],
1242 },
1243 )
1244 .await
1245 .expect_err("expected error"),
1246 Rejection::Client(_, ClientRejection::NotPermitted)
1247 );
1248
1249 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), false);
1250 }
1251
1252 #[fuchsia::test(allow_stalls = false)]
1253 async fn handle_mgmt_frame_bogus() {
1254 let (fake_device, _) = FakeDevice::new().await;
1255 let (mut ctx, _) = make_context(fake_device);
1256 let mut bss = make_infra_bss(&mut ctx).await;
1257
1258 assert_matches!(
1259 bss.handle_mgmt_frame(
1260 &mut ctx,
1261 mac::MgmtFrame {
1262 mgmt_hdr: mac::MgmtHdr {
1263 frame_ctrl: mac::FrameControl(0)
1264 .with_frame_type(mac::FrameType::MGMT)
1265 .with_mgmt_subtype(mac::MgmtSubtype::AUTH),
1266 duration: 0,
1267 addr1: (*BSSID).into(),
1268 addr2: *CLIENT_ADDR,
1269 addr3: (*BSSID).into(),
1270 seq_ctrl: mac::SequenceControl(10),
1271 }
1272 .as_bytes_ref(),
1273 ht_ctrl: None,
1274 body: &[][..],
1276 },
1277 )
1278 .await
1279 .expect_err("expected error"),
1280 Rejection::Client(_, ClientRejection::ParseFailed)
1281 );
1282
1283 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), false);
1284 }
1285
1286 #[fuchsia::test(allow_stalls = false)]
1287 async fn handle_data_frame() {
1288 let (fake_device, fake_device_state) = FakeDevice::new().await;
1289 let (mut ctx, _) = make_context(fake_device);
1290 let mut bss = make_infra_bss(&mut ctx).await;
1291
1292 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1293 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1294
1295 client
1297 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1298 .await
1299 .expect("expected OK");
1300 client
1301 .handle_mlme_assoc_resp(
1302 &mut ctx,
1303 false,
1304 1,
1305 mac::CapabilityInfo(0),
1306 fidl_mlme::AssociateResultCode::Success,
1307 1,
1308 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1309 )
1310 .await
1311 .expect("expected OK");
1312
1313 bss.handle_data_frame(
1314 &mut ctx,
1315 mac::DataFrame {
1316 fixed_fields: mac::FixedDataHdrFields {
1317 frame_ctrl: mac::FrameControl(0)
1318 .with_frame_type(mac::FrameType::DATA)
1319 .with_to_ds(true),
1320 duration: 0,
1321 addr1: (*BSSID).into(),
1322 addr2: *CLIENT_ADDR,
1323 addr3: *CLIENT_ADDR2,
1324 seq_ctrl: mac::SequenceControl(10),
1325 }
1326 .as_bytes_ref(),
1327 addr4: None,
1328 qos_ctrl: None,
1329 ht_ctrl: None,
1330 body: &[
1331 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1336 ][..],
1337 },
1338 )
1339 .expect("expected OK");
1340
1341 assert_eq!(fake_device_state.lock().eth_queue.len(), 1);
1342 assert_eq!(
1343 &fake_device_state.lock().eth_queue[0][..],
1344 &[
1345 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 0x12, 0x34, 1, 2, 3, 4, 5,
1350 ][..]
1351 );
1352 }
1353
1354 #[fuchsia::test(allow_stalls = false)]
1355 async fn handle_data_frame_bad_ds_bits() {
1356 let (fake_device, fake_device_state) = FakeDevice::new().await;
1357 let (mut ctx, _) = make_context(fake_device);
1358 let mut bss = make_infra_bss(&mut ctx).await;
1359
1360 assert_matches!(
1361 bss.handle_data_frame(
1362 &mut ctx,
1363 mac::DataFrame {
1364 fixed_fields: mac::FixedDataHdrFields {
1365 frame_ctrl: mac::FrameControl(0)
1366 .with_frame_type(mac::FrameType::DATA)
1367 .with_to_ds(false),
1368 duration: 0,
1369 addr1: (*BSSID).into(),
1370 addr2: *CLIENT_ADDR,
1371 addr3: *CLIENT_ADDR2,
1372 seq_ctrl: mac::SequenceControl(10),
1373 }
1374 .as_bytes_ref(),
1375 addr4: None,
1376 qos_ctrl: None,
1377 ht_ctrl: None,
1378 body: &[
1379 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1384 ][..],
1385 },
1386 )
1387 .expect_err("expected error"),
1388 Rejection::BadDsBits
1389 );
1390
1391 assert_eq!(fake_device_state.lock().eth_queue.len(), 0);
1392 }
1393
1394 #[fuchsia::test(allow_stalls = false)]
1395 async fn handle_client_event() {
1396 let (fake_device, fake_device_state) = FakeDevice::new().await;
1397 let (mut ctx, mut time_stream) = make_context(fake_device);
1398 let mut bss = make_infra_bss(&mut ctx).await;
1399
1400 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1401 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1402
1403 client
1405 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1406 .await
1407 .expect("expected OK");
1408 client
1409 .handle_mlme_assoc_resp(
1410 &mut ctx,
1411 false,
1412 1,
1413 mac::CapabilityInfo(0),
1414 fidl_mlme::AssociateResultCode::Success,
1415 1,
1416 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1417 )
1418 .await
1419 .expect("expected OK");
1420
1421 fake_device_state.lock().wlan_queue.clear();
1422
1423 let _ = time_stream.try_next().unwrap().expect("Should have scheduled a timeout");
1424 bss.handle_timed_event(
1425 &mut ctx,
1426 TimedEvent::ClientEvent(*CLIENT_ADDR, ClientEvent::BssIdleTimeout),
1427 )
1428 .await
1429 .expect("expected OK");
1430
1431 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1433 #[rustfmt::skip]
1434 assert_eq!(&fake_device_state.lock().wlan_queue[0].0[..], &[
1435 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, ][..]);
1445
1446 let msg = fake_device_state
1447 .lock()
1448 .next_mlme_msg::<fidl_mlme::DisassociateIndication>()
1449 .expect("expected MLME message");
1450 assert_eq!(
1451 msg,
1452 fidl_mlme::DisassociateIndication {
1453 peer_sta_address: CLIENT_ADDR.to_array(),
1454 reason_code: fidl_ieee80211::ReasonCode::ReasonInactivity,
1455 locally_initiated: true,
1456 },
1457 );
1458 }
1459
1460 #[fuchsia::test(allow_stalls = false)]
1461 async fn handle_data_frame_no_such_client() {
1462 let (fake_device, fake_device_state) = FakeDevice::new().await;
1463 let (mut ctx, _) = make_context(fake_device);
1464 let mut bss = make_infra_bss(&mut ctx).await;
1465
1466 assert_matches!(
1467 bss.handle_data_frame(
1468 &mut ctx,
1469 mac::DataFrame {
1470 fixed_fields: mac::FixedDataHdrFields {
1471 frame_ctrl: mac::FrameControl(0)
1472 .with_frame_type(mac::FrameType::DATA)
1473 .with_to_ds(true),
1474 duration: 0,
1475 addr1: (*BSSID).into(),
1476 addr2: *CLIENT_ADDR,
1477 addr3: *CLIENT_ADDR2,
1478 seq_ctrl: mac::SequenceControl(10),
1479 }
1480 .as_bytes_ref(),
1481 addr4: None,
1482 qos_ctrl: None,
1483 ht_ctrl: None,
1484 body: &[
1485 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1490 ][..],
1491 },
1492 )
1493 .expect_err("expected error"),
1494 Rejection::Client(_, ClientRejection::NotPermitted)
1495 );
1496
1497 assert_eq!(fake_device_state.lock().eth_queue.len(), 0);
1498
1499 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1500 assert_eq!(
1501 fake_device_state.lock().wlan_queue[0].0,
1502 &[
1503 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, ][..]
1513 );
1514 }
1515
1516 #[fuchsia::test(allow_stalls = false)]
1517 async fn handle_data_frame_client_not_associated() {
1518 let (fake_device, fake_device_state) = FakeDevice::new().await;
1519 let (mut ctx, _) = make_context(fake_device);
1520 let mut bss = make_infra_bss(&mut ctx).await;
1521
1522 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1523 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1524
1525 client
1528 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1529 .await
1530 .expect("expected OK");
1531
1532 fake_device_state.lock().wlan_queue.clear();
1533
1534 assert_matches!(
1535 bss.handle_data_frame(
1536 &mut ctx,
1537 mac::DataFrame {
1538 fixed_fields: mac::FixedDataHdrFields {
1539 frame_ctrl: mac::FrameControl(0)
1540 .with_frame_type(mac::FrameType::DATA)
1541 .with_to_ds(true),
1542 duration: 0,
1543 addr1: (*BSSID).into(),
1544 addr2: *CLIENT_ADDR,
1545 addr3: *CLIENT_ADDR2,
1546 seq_ctrl: mac::SequenceControl(10),
1547 }
1548 .as_bytes_ref(),
1549 addr4: None,
1550 qos_ctrl: None,
1551 ht_ctrl: None,
1552 body: &[
1553 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1558 ][..],
1559 },
1560 )
1561 .expect_err("expected error"),
1562 Rejection::Client(_, ClientRejection::NotPermitted)
1563 );
1564
1565 assert_eq!(fake_device_state.lock().eth_queue.len(), 0);
1566
1567 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1568 assert_eq!(
1569 fake_device_state.lock().wlan_queue[0].0,
1570 &[
1571 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, ][..]
1581 );
1582 }
1583
1584 #[fuchsia::test(allow_stalls = false)]
1585 async fn handle_eth_frame_no_rsn() {
1586 let (fake_device, fake_device_state) = FakeDevice::new().await;
1587 let (mut ctx, _) = make_context(fake_device);
1588 let mut bss = make_infra_bss(&mut ctx).await;
1589 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1590
1591 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1592 client
1593 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1594 .await
1595 .expect("expected OK");
1596 client
1597 .handle_mlme_assoc_resp(
1598 &mut ctx,
1599 false,
1600 1,
1601 mac::CapabilityInfo(0),
1602 fidl_mlme::AssociateResultCode::Success,
1603 1,
1604 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1605 )
1606 .await
1607 .expect("expected OK");
1608 fake_device_state.lock().wlan_queue.clear();
1609
1610 bss.handle_eth_frame(
1611 &mut ctx,
1612 EthernetIIHdr {
1613 da: *CLIENT_ADDR,
1614 sa: *CLIENT_ADDR2,
1615 ether_type: BigEndianU16::new(0x1234),
1616 },
1617 &[1, 2, 3, 4, 5][..],
1618 0.into(),
1619 )
1620 .expect("expected OK");
1621
1622 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1623 assert_eq!(
1624 &fake_device_state.lock().wlan_queue[0].0[..],
1625 &[
1626 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,
1638 ][..]
1639 );
1640 }
1641
1642 #[fuchsia::test(allow_stalls = false)]
1643 async fn handle_eth_frame_no_client() {
1644 let (fake_device, fake_device_state) = FakeDevice::new().await;
1645 let (mut ctx, _) = make_context(fake_device);
1646 let mut bss = make_infra_bss(&mut ctx).await;
1647
1648 assert_matches!(
1649 bss.handle_eth_frame(
1650 &mut ctx,
1651 EthernetIIHdr {
1652 da: *CLIENT_ADDR,
1653 sa: *CLIENT_ADDR2,
1654 ether_type: BigEndianU16::new(0x1234)
1655 },
1656 &[1, 2, 3, 4, 5][..],
1657 0.into(),
1658 )
1659 .expect_err("expected error"),
1660 Rejection::Client(_, ClientRejection::NotAssociated)
1661 );
1662
1663 assert_eq!(fake_device_state.lock().wlan_queue.len(), 0);
1664 }
1665
1666 #[fuchsia::test(allow_stalls = false)]
1667 async fn handle_eth_frame_is_rsn_eapol_controlled_port_closed() {
1668 let (fake_device, fake_device_state) = FakeDevice::new().await;
1669 let (mut ctx, _) = make_context(fake_device);
1670 let mut bss = make_protected_infra_bss(&mut ctx).await;
1671 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1672
1673 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1674 client
1675 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1676 .await
1677 .expect("expected OK");
1678 client
1679 .handle_mlme_assoc_resp(
1680 &mut ctx,
1681 true,
1682 1,
1683 mac::CapabilityInfo(0),
1684 fidl_mlme::AssociateResultCode::Success,
1685 1,
1686 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1687 )
1688 .await
1689 .expect("expected OK");
1690 fake_device_state.lock().wlan_queue.clear();
1691
1692 assert_matches!(
1693 bss.handle_eth_frame(
1694 &mut ctx,
1695 EthernetIIHdr {
1696 da: *CLIENT_ADDR,
1697 sa: *CLIENT_ADDR2,
1698 ether_type: BigEndianU16::new(0x1234)
1699 },
1700 &[1, 2, 3, 4, 5][..],
1701 0.into(),
1702 )
1703 .expect_err("expected error"),
1704 Rejection::Client(_, ClientRejection::ControlledPortClosed)
1705 );
1706 }
1707
1708 #[fuchsia::test(allow_stalls = false)]
1709 async fn handle_eth_frame_is_rsn_eapol_controlled_port_open() {
1710 let (fake_device, fake_device_state) = FakeDevice::new().await;
1711 let (mut ctx, _) = make_context(fake_device);
1712 let mut bss = make_protected_infra_bss(&mut ctx).await;
1713 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1714
1715 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1716 client
1717 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1718 .await
1719 .expect("expected OK");
1720 client
1721 .handle_mlme_assoc_resp(
1722 &mut ctx,
1723 true,
1724 1,
1725 mac::CapabilityInfo(0),
1726 fidl_mlme::AssociateResultCode::Success,
1727 1,
1728 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1729 )
1730 .await
1731 .expect("expected OK");
1732 fake_device_state.lock().wlan_queue.clear();
1733
1734 client
1735 .handle_mlme_set_controlled_port_req(fidl_mlme::ControlledPortState::Open)
1736 .expect("expected OK");
1737
1738 bss.handle_eth_frame(
1739 &mut ctx,
1740 EthernetIIHdr {
1741 da: *CLIENT_ADDR,
1742 sa: *CLIENT_ADDR2,
1743 ether_type: BigEndianU16::new(0x1234),
1744 },
1745 &[1, 2, 3, 4, 5][..],
1746 0.into(),
1747 )
1748 .expect("expected OK");
1749
1750 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1751 assert_eq!(
1752 &fake_device_state.lock().wlan_queue[0].0[..],
1753 &[
1754 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,
1766 ][..]
1767 );
1768 }
1769
1770 #[test_case(false; "Controlled port closed")]
1771 #[test_case(true; "Controlled port open")]
1772 #[fuchsia::test(allow_stalls = false)]
1773 async fn handle_data_frame_is_rsn_eapol(controlled_port_open: bool) {
1774 let (fake_device, fake_device_state) = FakeDevice::new().await;
1775 let (mut ctx, _) = make_context(fake_device);
1776 let mut bss = make_protected_infra_bss(&mut ctx).await;
1777 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1778
1779 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1780 client
1781 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1782 .await
1783 .expect("expected OK");
1784 client
1785 .handle_mlme_assoc_resp(
1786 &mut ctx,
1787 true,
1788 1,
1789 mac::CapabilityInfo(0),
1790 fidl_mlme::AssociateResultCode::Success,
1791 1,
1792 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1793 )
1794 .await
1795 .expect("expected OK");
1796 fake_device_state.lock().wlan_queue.clear();
1797
1798 if controlled_port_open {
1799 client
1800 .handle_mlme_set_controlled_port_req(fidl_mlme::ControlledPortState::Open)
1801 .expect("expected OK");
1802 }
1803
1804 bss.handle_data_frame(
1805 &mut ctx,
1806 mac::DataFrame {
1807 fixed_fields: mac::FixedDataHdrFields {
1808 frame_ctrl: mac::FrameControl(0)
1809 .with_frame_type(mac::FrameType::DATA)
1810 .with_to_ds(true),
1811 duration: 0,
1812 addr1: (*BSSID).into(),
1813 addr2: *CLIENT_ADDR,
1814 addr3: *CLIENT_ADDR2,
1815 seq_ctrl: mac::SequenceControl(10),
1816 }
1817 .as_bytes_ref(),
1818 addr4: None,
1819 qos_ctrl: None,
1820 ht_ctrl: None,
1821 body: &[
1822 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1827 ][..],
1828 },
1829 )
1830 .expect("expected OK");
1831
1832 if controlled_port_open {
1833 assert_eq!(fake_device_state.lock().eth_queue.len(), 1);
1834 } else {
1835 assert!(fake_device_state.lock().eth_queue.is_empty());
1836 }
1837 }
1838
1839 async fn authenticate_client(
1840 fake_device_state: Arc<Mutex<FakeDeviceState>>,
1841 ctx: &mut Context<FakeDevice>,
1842 bss: &mut InfraBss,
1843 client_addr: MacAddr,
1844 ) {
1845 bss.handle_mgmt_frame(
1846 ctx,
1847 mac::MgmtFrame {
1848 mgmt_hdr: mac::MgmtHdr {
1849 frame_ctrl: mac::FrameControl(0)
1850 .with_frame_type(mac::FrameType::MGMT)
1851 .with_mgmt_subtype(mac::MgmtSubtype::AUTH),
1852 duration: 0,
1853 addr1: (*BSSID).into(),
1854 addr2: client_addr,
1855 addr3: (*BSSID).into(),
1856 seq_ctrl: mac::SequenceControl(10),
1857 }
1858 .as_bytes_ref(),
1859 ht_ctrl: None,
1860 body: &[
1861 0, 0, 1, 0, 0, 0, ][..],
1866 },
1867 )
1868 .await
1869 .expect("failed to handle auth req frame");
1870
1871 fake_device_state
1872 .lock()
1873 .next_mlme_msg::<fidl_mlme::AuthenticateIndication>()
1874 .expect("expected auth indication");
1875 bss.handle_mlme_auth_resp(
1876 ctx,
1877 fidl_mlme::AuthenticateResponse {
1878 peer_sta_address: client_addr.to_array(),
1879 result_code: fidl_mlme::AuthenticateResultCode::Success,
1880 },
1881 )
1882 .await
1883 .expect("failed to handle auth resp");
1884 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1885 fake_device_state.lock().wlan_queue.clear();
1886 }
1887
1888 async fn associate_client(
1889 fake_device_state: Arc<Mutex<FakeDeviceState>>,
1890 ctx: &mut Context<FakeDevice>,
1891 bss: &mut InfraBss,
1892 client_addr: MacAddr,
1893 association_id: u16,
1894 ) {
1895 bss.handle_mgmt_frame(
1896 ctx,
1897 mac::MgmtFrame {
1898 mgmt_hdr: mac::MgmtHdr {
1899 frame_ctrl: mac::FrameControl(0)
1900 .with_frame_type(mac::FrameType::MGMT)
1901 .with_mgmt_subtype(mac::MgmtSubtype::ASSOC_REQ),
1902 duration: 0,
1903 addr1: (*BSSID).into(),
1904 addr2: client_addr,
1905 addr3: (*BSSID).into(),
1906 seq_ctrl: mac::SequenceControl(10),
1907 }
1908 .as_bytes_ref(),
1909 ht_ctrl: None,
1910 body: &[
1911 0, 0, 10, 0, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 2, 9, 10, 48, 2, 77, 88, ][..],
1919 },
1920 )
1921 .await
1922 .expect("expected OK");
1923 let msg = fake_device_state
1924 .lock()
1925 .next_mlme_msg::<fidl_mlme::AssociateIndication>()
1926 .expect("expected assoc indication");
1927 bss.handle_mlme_assoc_resp(
1928 ctx,
1929 fidl_mlme::AssociateResponse {
1930 peer_sta_address: client_addr.to_array(),
1931 result_code: fidl_mlme::AssociateResultCode::Success,
1932 association_id,
1933 capability_info: msg.capability_info,
1934 rates: msg.rates,
1935 },
1936 )
1937 .await
1938 .expect("failed to handle assoc resp");
1939 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1940 fake_device_state.lock().wlan_queue.clear();
1941 }
1942
1943 fn send_eth_frame_from_ds_to_client(
1944 ctx: &mut Context<FakeDevice>,
1945 bss: &mut InfraBss,
1946 client_addr: MacAddr,
1947 ) {
1948 bss.handle_eth_frame(
1949 ctx,
1950 EthernetIIHdr {
1951 da: client_addr,
1952 sa: *REMOTE_ADDR,
1953 ether_type: BigEndianU16::new(0x1234),
1954 },
1955 &[1, 2, 3, 4, 5][..],
1956 0.into(),
1957 )
1958 .expect("expected OK");
1959 }
1960
1961 #[fuchsia::test(allow_stalls = false)]
1962 async fn handle_multiple_complete_associations() {
1963 let (fake_device, fake_device_state) = FakeDevice::new().await;
1964 let (mut ctx, _) = make_context(fake_device);
1965 let mut bss = make_infra_bss(&mut ctx).await;
1966
1967 authenticate_client(fake_device_state.clone(), &mut ctx, &mut bss, *CLIENT_ADDR).await;
1968 authenticate_client(fake_device_state.clone(), &mut ctx, &mut bss, *CLIENT_ADDR2).await;
1969
1970 associate_client(fake_device_state.clone(), &mut ctx, &mut bss, *CLIENT_ADDR, 1).await;
1971 associate_client(fake_device_state.clone(), &mut ctx, &mut bss, *CLIENT_ADDR2, 2).await;
1972
1973 assert!(bss.clients.contains_key(&CLIENT_ADDR));
1974 assert!(bss.clients.contains_key(&CLIENT_ADDR2));
1975
1976 send_eth_frame_from_ds_to_client(&mut ctx, &mut bss, *CLIENT_ADDR);
1977 send_eth_frame_from_ds_to_client(&mut ctx, &mut bss, *CLIENT_ADDR2);
1978
1979 assert_eq!(fake_device_state.lock().wlan_queue.len(), 2);
1980 }
1981
1982 #[fuchsia::test(allow_stalls = false)]
1983 async fn handle_ps_poll() {
1984 let (fake_device, fake_device_state) = FakeDevice::new().await;
1985 let (mut ctx, _) = make_context(fake_device);
1986 let mut bss = make_infra_bss(&mut ctx).await;
1987 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1988
1989 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1990 client
1991 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1992 .await
1993 .expect("expected OK");
1994 client
1995 .handle_mlme_assoc_resp(
1996 &mut ctx,
1997 false,
1998 1,
1999 mac::CapabilityInfo(0),
2000 fidl_mlme::AssociateResultCode::Success,
2001 1,
2002 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
2003 )
2004 .await
2005 .expect("expected OK");
2006 client.set_power_state(&mut ctx, mac::PowerState::DOZE).expect("expected doze ok");
2007 fake_device_state.lock().wlan_queue.clear();
2008
2009 bss.handle_eth_frame(
2010 &mut ctx,
2011 EthernetIIHdr {
2012 da: *CLIENT_ADDR,
2013 sa: *CLIENT_ADDR2,
2014 ether_type: BigEndianU16::new(0x1234),
2015 },
2016 &[1, 2, 3, 4, 5][..],
2017 0.into(),
2018 )
2019 .expect("expected OK");
2020 assert_eq!(fake_device_state.lock().wlan_queue.len(), 0);
2021
2022 bss.handle_ctrl_frame(
2023 &mut ctx,
2024 mac::CtrlFrame {
2025 frame_ctrl: mac::FrameControl(0)
2026 .with_frame_type(mac::FrameType::CTRL)
2027 .with_ctrl_subtype(mac::CtrlSubtype::PS_POLL),
2028 body: &[
2029 0b00000001, 0b11000000, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, ][..],
2033 },
2034 )
2035 .expect("expected OK");
2036 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
2037 assert_eq!(
2038 &fake_device_state.lock().wlan_queue[0].0[..],
2039 &[
2040 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,
2052 ][..]
2053 );
2054 }
2055
2056 #[fuchsia::test(allow_stalls = false)]
2057 async fn handle_mlme_setkeys_req() {
2058 let (fake_device, fake_device_state) = FakeDevice::new().await;
2059 let (mut ctx, _) = make_context(fake_device);
2060 let mut bss = make_protected_infra_bss(&mut ctx).await;
2061 bss.handle_mlme_setkeys_req(
2062 &mut ctx,
2063 vec![fidl_mlme::SetKeyDescriptor {
2064 cipher_suite_oui: [1, 2, 3],
2065 cipher_suite_type: fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
2066 key_type: fidl_mlme::KeyType::Pairwise,
2067 address: [5; 6].into(),
2068 key_id: 6,
2069 key: vec![1, 2, 3, 4, 5, 6, 7],
2070 rsc: 8,
2071 }],
2072 )
2073 .await
2074 .expect("expected InfraBss::handle_mlme_setkeys_req OK");
2075 assert_eq!(
2076 fake_device_state.lock().keys,
2077 vec![fidl_softmac::WlanKeyConfiguration {
2078 protection: Some(fidl_softmac::WlanProtection::RxTx),
2079 cipher_oui: Some([1, 2, 3]),
2080 cipher_type: Some(4),
2081 key_type: Some(fidl_ieee80211::KeyType::Pairwise),
2082 peer_addr: Some([5; 6]),
2083 key_idx: Some(6),
2084 key: Some(vec![1, 2, 3, 4, 5, 6, 7]),
2085 rsc: Some(8),
2086 ..Default::default()
2087 }]
2088 );
2089 }
2090
2091 #[fuchsia::test(allow_stalls = false)]
2092 async fn handle_mlme_setkeys_req_no_rsne() {
2093 let (fake_device, fake_device_state) = FakeDevice::new().await;
2094 let (mut ctx, _) = make_context(fake_device);
2095 let mut bss = make_infra_bss(&mut ctx).await;
2096 assert_matches!(
2097 bss.handle_mlme_setkeys_req(
2098 &mut ctx,
2099 vec![fidl_mlme::SetKeyDescriptor {
2100 cipher_suite_oui: [1, 2, 3],
2101 cipher_suite_type:
2102 fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
2103 key_type: fidl_mlme::KeyType::Pairwise,
2104 address: [5; 6],
2105 key_id: 6,
2106 key: vec![1, 2, 3, 4, 5, 6, 7],
2107 rsc: 8,
2108 }]
2109 )
2110 .await
2111 .expect_err("expected InfraBss::handle_mlme_setkeys_req error"),
2112 Error::Status(_, zx::Status::BAD_STATE)
2113 );
2114 assert!(fake_device_state.lock().keys.is_empty());
2115 }
2116
2117 #[fuchsia::test(allow_stalls = false)]
2118 async fn handle_probe_req() {
2119 let (fake_device, fake_device_state) = FakeDevice::new().await;
2120 let (mut ctx, _) = make_context(fake_device);
2121 let mut bss = InfraBss::new(
2122 &mut ctx,
2123 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2124 TimeUnit::DEFAULT_BEACON_INTERVAL,
2125 2,
2126 mac::CapabilityInfo(33),
2127 vec![248],
2128 1,
2129 Some(vec![48, 2, 77, 88]),
2130 )
2131 .await
2132 .expect("expected InfraBss::new ok");
2133
2134 bss.handle_probe_req(&mut ctx, *CLIENT_ADDR)
2135 .expect("expected InfraBss::handle_probe_req ok");
2136 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
2137 assert_eq!(
2138 &fake_device_state.lock().wlan_queue[0].0[..],
2139 &[
2140 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, ][..]
2157 );
2158 }
2159
2160 #[fuchsia::test(allow_stalls = false)]
2161 async fn handle_probe_req_has_offload() {
2162 let (fake_device, _fake_device_state) = FakeDevice::new_with_config(
2163 FakeDeviceConfig::default().with_mock_probe_response_offload(
2164 fidl_softmac::ProbeResponseOffloadExtension {
2165 supported: Some(true),
2166 ..Default::default()
2167 },
2168 ),
2169 )
2170 .await;
2171
2172 let (mut ctx, _) = make_context(fake_device);
2173 let mut bss = InfraBss::new(
2174 &mut ctx,
2175 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2176 TimeUnit::DEFAULT_BEACON_INTERVAL,
2177 2,
2178 CapabilityInfo(33),
2179 vec![0b11111000],
2180 1,
2181 Some(vec![48, 2, 77, 88]),
2182 )
2183 .await
2184 .expect("expected InfraBss::new ok");
2185
2186 bss.handle_mgmt_frame(
2187 &mut ctx,
2188 mac::MgmtFrame {
2189 mgmt_hdr: mac::MgmtHdr {
2190 frame_ctrl: mac::FrameControl(0)
2191 .with_frame_type(mac::FrameType::MGMT)
2192 .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
2193 duration: 0,
2194 addr1: (*BSSID).into(),
2195 addr2: *CLIENT_ADDR,
2196 addr3: (*BSSID).into(),
2197 seq_ctrl: mac::SequenceControl(10),
2198 }
2199 .as_bytes_ref(),
2200 ht_ctrl: None,
2201 body: &[][..],
2202 },
2203 )
2204 .await
2205 .expect_err("expected InfraBss::handle_mgmt_frame error");
2206 }
2207
2208 #[fuchsia::test(allow_stalls = false)]
2209 async fn handle_probe_req_wildcard_ssid() {
2210 let (fake_device, fake_device_state) = FakeDevice::new().await;
2211 let (mut ctx, _) = make_context(fake_device);
2212 let mut bss = InfraBss::new(
2213 &mut ctx,
2214 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2215 TimeUnit::DEFAULT_BEACON_INTERVAL,
2216 2,
2217 CapabilityInfo(33),
2218 vec![0b11111000],
2219 1,
2220 Some(vec![48, 2, 77, 88]),
2221 )
2222 .await
2223 .expect("expected InfraBss::new ok");
2224
2225 bss.handle_mgmt_frame(
2226 &mut ctx,
2227 mac::MgmtFrame {
2228 mgmt_hdr: mac::MgmtHdr {
2229 frame_ctrl: mac::FrameControl(0)
2230 .with_frame_type(mac::FrameType::MGMT)
2231 .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
2232 duration: 0,
2233 addr1: (*BSSID).into(),
2234 addr2: *CLIENT_ADDR,
2235 addr3: (*BSSID).into(),
2236 seq_ctrl: mac::SequenceControl(10),
2237 }
2238 .as_bytes_ref(),
2239 ht_ctrl: None,
2240 body: &[
2241 0, 0, ][..],
2243 },
2244 )
2245 .await
2246 .expect("expected InfraBss::handle_mgmt_frame ok");
2247
2248 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
2249 assert_eq!(
2250 &fake_device_state.lock().wlan_queue[0].0[..],
2251 &[
2252 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, ][..]
2269 );
2270 }
2271
2272 #[fuchsia::test(allow_stalls = false)]
2273 async fn handle_probe_req_matching_ssid() {
2274 let (fake_device, fake_device_state) = FakeDevice::new().await;
2275 let (mut ctx, _) = make_context(fake_device);
2276 let mut bss = InfraBss::new(
2277 &mut ctx,
2278 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2279 TimeUnit::DEFAULT_BEACON_INTERVAL,
2280 2,
2281 CapabilityInfo(33),
2282 vec![0b11111000],
2283 1,
2284 Some(vec![48, 2, 77, 88]),
2285 )
2286 .await
2287 .expect("expected InfraBss::new ok");
2288
2289 bss.handle_mgmt_frame(
2290 &mut ctx,
2291 mac::MgmtFrame {
2292 mgmt_hdr: mac::MgmtHdr {
2293 frame_ctrl: mac::FrameControl(0)
2294 .with_frame_type(mac::FrameType::MGMT)
2295 .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
2296 duration: 0,
2297 addr1: (*BSSID).into(),
2298 addr2: *CLIENT_ADDR,
2299 addr3: (*BSSID).into(),
2300 seq_ctrl: mac::SequenceControl(10),
2301 }
2302 .as_bytes_ref(),
2303 ht_ctrl: None,
2304 body: &[0, 5, 1, 2, 3, 4, 5][..],
2305 },
2306 )
2307 .await
2308 .expect("expected InfraBss::handle_mgmt_frame ok");
2309
2310 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
2311 assert_eq!(
2312 &fake_device_state.lock().wlan_queue[0].0[..],
2313 &[
2314 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, ][..]
2331 );
2332 }
2333
2334 #[fuchsia::test(allow_stalls = false)]
2335 async fn handle_probe_req_mismatching_ssid() {
2336 let (fake_device, _) = FakeDevice::new().await;
2337 let (mut ctx, _) = make_context(fake_device);
2338 let mut bss = InfraBss::new(
2339 &mut ctx,
2340 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2341 TimeUnit::DEFAULT_BEACON_INTERVAL,
2342 2,
2343 CapabilityInfo(33),
2344 vec![0b11111000],
2345 1,
2346 Some(vec![48, 2, 77, 88]),
2347 )
2348 .await
2349 .expect("expected InfraBss::new ok");
2350
2351 assert_matches!(
2352 bss.handle_mgmt_frame(
2353 &mut ctx,
2354 mac::MgmtFrame {
2355 mgmt_hdr: mac::MgmtHdr {
2356 frame_ctrl: mac::FrameControl(0)
2357 .with_frame_type(mac::FrameType::MGMT)
2358 .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
2359 duration: 0,
2360 addr1: (*BSSID).into(),
2361 addr2: *CLIENT_ADDR,
2362 addr3: (*BSSID).into(),
2363 seq_ctrl: mac::SequenceControl(10),
2364 }
2365 .as_bytes_ref(),
2366 ht_ctrl: None,
2367 body: &[0, 5, 1, 2, 3, 4, 6][..],
2368 },
2369 )
2370 .await
2371 .expect_err("expected InfraBss::handle_mgmt_frame error"),
2372 Rejection::OtherBss
2373 );
2374 }
2375
2376 #[fuchsia::test(allow_stalls = false)]
2377 async fn make_tim() {
2378 let (fake_device, _) = FakeDevice::new().await;
2379 let (mut ctx, _) = make_context(fake_device);
2380 let mut bss = make_infra_bss(&mut ctx).await;
2381 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
2382
2383 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
2384 client
2385 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
2386 .await
2387 .expect("expected OK");
2388 client
2389 .handle_mlme_assoc_resp(
2390 &mut ctx,
2391 false,
2392 1,
2393 mac::CapabilityInfo(0),
2394 fidl_mlme::AssociateResultCode::Success,
2395 1,
2396 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
2397 )
2398 .await
2399 .expect("expected OK");
2400 client.set_power_state(&mut ctx, mac::PowerState::DOZE).expect("expected doze OK");
2401
2402 bss.handle_eth_frame(
2403 &mut ctx,
2404 EthernetIIHdr {
2405 da: *CLIENT_ADDR,
2406 sa: *CLIENT_ADDR2,
2407 ether_type: BigEndianU16::new(0x1234),
2408 },
2409 &[1, 2, 3, 4, 5][..],
2410 0.into(),
2411 )
2412 .expect("expected OK");
2413
2414 let tim = bss.make_tim();
2415 let (pvb_offset, pvb_bitmap) = tim.make_partial_virtual_bitmap();
2416 assert_eq!(pvb_offset, 0);
2417 assert_eq!(pvb_bitmap, &[0b00000010][..]);
2418 }
2419
2420 #[fuchsia::test(allow_stalls = false)]
2421 async fn make_tim_empty() {
2422 let (fake_device, _) = FakeDevice::new().await;
2423 let (mut ctx, _) = make_context(fake_device);
2424 let bss = make_infra_bss(&mut ctx).await;
2425
2426 let tim = bss.make_tim();
2427 let (pvb_offset, pvb_bitmap) = tim.make_partial_virtual_bitmap();
2428 assert_eq!(pvb_offset, 0);
2429 assert_eq!(pvb_bitmap, &[0b00000000][..]);
2430 }
2431}