1use crate::ap::remote_client::{ClientRejection, RemoteClient};
6use crate::ap::{frame_writer, BeaconOffloadParams, BufferedFrame, Context, Rejection, TimedEvent};
7use crate::ddk_converter::softmac_key_configuration_from_mlme;
8use crate::device::{self, DeviceOps};
9use crate::error::Error;
10use crate::WlanTxPacketExt as _;
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::{ie, tim, TimeUnit};
19use zerocopy::SplitByteSlice;
20use {
21 fidl_fuchsia_wlan_common as fidl_common, 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_common::WlanChannel {
83 primary: channel,
84
85 cbw: fidl_common::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(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(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.to_native(),
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(RemoteClient::new(hdr.da)));
565 client
566 .handle_eth_frame(ctx, hdr.da, hdr.sa, hdr.ether_type.to_native(), 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 fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
619 use fuchsia_sync::Mutex;
620 use ieee80211::Bssid;
621 use lazy_static::lazy_static;
622 use std::sync::Arc;
623 use test_case::test_case;
624 use wlan_common::assert_variant;
625 use wlan_common::big_endian::BigEndianU16;
626 use wlan_common::mac::IntoBytesExt as _;
627 use wlan_common::test_utils::fake_frames::fake_wpa2_rsne;
628 use wlan_common::timer::{self, create_timer};
629
630 lazy_static! {
631 static ref CLIENT_ADDR: MacAddr = [4u8; 6].into();
632 static ref BSSID: Bssid = [2u8; 6].into();
633 static ref CLIENT_ADDR2: MacAddr = [6u8; 6].into();
634 static ref REMOTE_ADDR: MacAddr = [123u8; 6].into();
635 }
636
637 fn make_context(
638 fake_device: FakeDevice,
639 ) -> (Context<FakeDevice>, timer::EventStream<TimedEvent>) {
640 let (timer, time_stream) = create_timer();
641 (Context::new(fake_device, timer, *BSSID), time_stream)
642 }
643
644 async fn make_infra_bss(ctx: &mut Context<FakeDevice>) -> InfraBss {
645 InfraBss::new(
646 ctx,
647 Ssid::try_from("coolnet").unwrap(),
648 TimeUnit::DEFAULT_BEACON_INTERVAL,
649 2,
650 CapabilityInfo(0),
651 vec![0b11111000],
652 1,
653 None,
654 )
655 .await
656 .expect("expected InfraBss::new ok")
657 }
658
659 async fn make_protected_infra_bss(ctx: &mut Context<FakeDevice>) -> InfraBss {
660 InfraBss::new(
661 ctx,
662 Ssid::try_from("coolnet").unwrap(),
663 TimeUnit::DEFAULT_BEACON_INTERVAL,
664 2,
665 CapabilityInfo(0),
666 vec![0b11111000],
667 1,
668 Some(fake_wpa2_rsne()),
669 )
670 .await
671 .expect("expected InfraBss::new ok")
672 }
673
674 #[fuchsia::test(allow_stalls = false)]
675 async fn new() {
676 let (fake_device, fake_device_state) = FakeDevice::new().await;
677 let (mut ctx, _) = make_context(fake_device);
678 InfraBss::new(
679 &mut ctx,
680 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
681 TimeUnit::DEFAULT_BEACON_INTERVAL,
682 2,
683 CapabilityInfo(0).with_ess(true),
684 vec![0b11111000],
685 1,
686 None,
687 )
688 .await
689 .expect("expected InfraBss::new ok");
690
691 assert_eq!(
692 fake_device_state.lock().wlan_channel,
693 fidl_common::WlanChannel {
694 primary: 1,
695 cbw: fidl_common::ChannelBandwidth::Cbw20,
696 secondary80: 0
697 }
698 );
699
700 let beacon_tmpl = vec![
701 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, ];
718
719 assert_eq!(
720 fake_device_state.lock().beacon_config.as_ref().expect("expected beacon_config"),
721 &(beacon_tmpl, 49, TimeUnit::DEFAULT_BEACON_INTERVAL)
722 );
723 }
724
725 #[fuchsia::test(allow_stalls = false)]
726 async fn stop() {
727 let (fake_device, fake_device_state) = FakeDevice::new().await;
728 let (mut ctx, _) = make_context(fake_device);
729 let bss = make_infra_bss(&mut ctx).await;
730 bss.stop(&mut ctx).await.expect("expected InfraBss::stop ok");
731 assert!(fake_device_state.lock().beacon_config.is_none());
732 }
733
734 #[fuchsia::test(allow_stalls = false)]
735 async fn handle_mlme_auth_resp() {
736 let (fake_device, fake_device_state) = FakeDevice::new().await;
737 let (mut ctx, _) = make_context(fake_device);
738 let mut bss = make_infra_bss(&mut ctx).await;
739
740 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
741
742 bss.handle_mlme_auth_resp(
743 &mut ctx,
744 fidl_mlme::AuthenticateResponse {
745 peer_sta_address: CLIENT_ADDR.to_array(),
746 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
747 },
748 )
749 .await
750 .expect("expected InfraBss::handle_mlme_auth_resp ok");
751 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
752 assert_eq!(
753 &fake_device_state.lock().wlan_queue[0].0[..],
754 &[
755 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, ][..]
767 );
768 }
769
770 #[fuchsia::test(allow_stalls = false)]
771 async fn handle_mlme_auth_resp_no_such_client() {
772 let (fake_device, _) = FakeDevice::new().await;
773 let (mut ctx, _) = make_context(fake_device);
774 let mut bss = make_infra_bss(&mut ctx).await;
775
776 assert_eq!(
777 zx::Status::from(
778 bss.handle_mlme_auth_resp(
779 &mut ctx,
780 fidl_mlme::AuthenticateResponse {
781 peer_sta_address: CLIENT_ADDR.to_array(),
782 result_code: fidl_mlme::AuthenticateResultCode::AntiCloggingTokenRequired,
783 },
784 )
785 .await
786 .expect_err("expected InfraBss::handle_mlme_auth_resp error")
787 ),
788 zx::Status::NOT_FOUND
789 );
790 }
791
792 #[fuchsia::test(allow_stalls = false)]
793 async fn handle_mlme_deauth_req() {
794 let (fake_device, fake_device_state) = FakeDevice::new().await;
795 let (mut ctx, _) = make_context(fake_device);
796 let mut bss = make_infra_bss(&mut ctx).await;
797
798 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
799
800 bss.handle_mlme_deauth_req(
801 &mut ctx,
802 fidl_mlme::DeauthenticateRequest {
803 peer_sta_address: CLIENT_ADDR.to_array(),
804 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
805 },
806 )
807 .await
808 .expect("expected InfraBss::handle_mlme_deauth_req ok");
809 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
810 assert_eq!(
811 &fake_device_state.lock().wlan_queue[0].0[..],
812 &[
813 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, ][..]
823 );
824
825 assert!(!bss.clients.contains_key(&CLIENT_ADDR));
826 }
827
828 #[fuchsia::test(allow_stalls = false)]
829 async fn handle_mlme_assoc_resp() {
830 let (fake_device, fake_device_state) = FakeDevice::new().await;
831 let (mut ctx, _) = make_context(fake_device);
832 let mut bss = make_infra_bss(&mut ctx).await;
833
834 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
835 bss.handle_mlme_assoc_resp(
836 &mut ctx,
837 fidl_mlme::AssociateResponse {
838 peer_sta_address: CLIENT_ADDR.to_array(),
839 result_code: fidl_mlme::AssociateResultCode::Success,
840 association_id: 1,
841 capability_info: 0,
842 rates: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
843 },
844 )
845 .await
846 .expect("expected InfraBss::handle_mlme_assoc_resp ok");
847 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
848 assert_eq!(
849 &fake_device_state.lock().wlan_queue[0].0[..],
850 &[
851 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, ][..]
867 );
868 assert!(fake_device_state.lock().assocs.contains_key(&CLIENT_ADDR));
869 }
870
871 #[fuchsia::test(allow_stalls = false)]
872 async fn handle_mlme_assoc_resp_with_caps() {
873 let (fake_device, fake_device_state) = FakeDevice::new().await;
874 let (mut ctx, _) = make_context(fake_device);
875 let mut bss = InfraBss::new(
876 &mut ctx,
877 Ssid::try_from("coolnet").unwrap(),
878 TimeUnit::DEFAULT_BEACON_INTERVAL,
879 2,
880 CapabilityInfo(0).with_short_preamble(true).with_ess(true),
881 vec![0b11111000],
882 1,
883 None,
884 )
885 .await
886 .expect("expected InfraBss::new ok");
887
888 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
889
890 bss.handle_mlme_assoc_resp(
891 &mut ctx,
892 fidl_mlme::AssociateResponse {
893 peer_sta_address: CLIENT_ADDR.to_array(),
894 result_code: fidl_mlme::AssociateResultCode::Success,
895 association_id: 1,
896 capability_info: CapabilityInfo(0).with_short_preamble(true).raw(),
897 rates: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
898 },
899 )
900 .await
901 .expect("expected InfraBss::handle_mlme_assoc_resp ok");
902 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
903 assert_eq!(
904 &fake_device_state.lock().wlan_queue[0].0[..],
905 &[
906 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, ][..]
922 );
923 assert!(fake_device_state.lock().assocs.contains_key(&CLIENT_ADDR));
924 }
925
926 #[fuchsia::test(allow_stalls = false)]
927 async fn handle_mlme_disassoc_req() {
928 let (fake_device, fake_device_state) = FakeDevice::new().await;
929 let (mut ctx, _) = make_context(fake_device);
930 let mut bss = make_infra_bss(&mut ctx).await;
931
932 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
933
934 bss.handle_mlme_disassoc_req(
935 &mut ctx,
936 fidl_mlme::DisassociateRequest {
937 peer_sta_address: CLIENT_ADDR.to_array(),
938 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDisassoc,
939 },
940 )
941 .await
942 .expect("expected InfraBss::handle_mlme_disassoc_req ok");
943 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
944 assert_eq!(
945 &fake_device_state.lock().wlan_queue[0].0[..],
946 &[
947 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, ][..]
957 );
958 }
959
960 #[fuchsia::test(allow_stalls = false)]
961 async fn handle_mlme_set_controlled_port_req() {
962 let (fake_device, _) = FakeDevice::new().await;
963 let (mut ctx, _) = make_context(fake_device);
964 let mut bss = make_protected_infra_bss(&mut ctx).await;
965
966 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
967
968 bss.handle_mlme_assoc_resp(
969 &mut ctx,
970 fidl_mlme::AssociateResponse {
971 peer_sta_address: CLIENT_ADDR.to_array(),
972 result_code: fidl_mlme::AssociateResultCode::Success,
973 association_id: 1,
974 capability_info: 0,
975 rates: vec![1, 2, 3],
976 },
977 )
978 .await
979 .expect("expected InfraBss::handle_mlme_assoc_resp ok");
980
981 bss.handle_mlme_set_controlled_port_req(fidl_mlme::SetControlledPortRequest {
982 peer_sta_address: CLIENT_ADDR.to_array(),
983 state: fidl_mlme::ControlledPortState::Open,
984 })
985 .expect("expected InfraBss::handle_mlme_set_controlled_port_req ok");
986 }
987
988 #[fuchsia::test(allow_stalls = false)]
989 async fn handle_mlme_eapol_req() {
990 let (fake_device, fake_device_state) = FakeDevice::new().await;
991 let (mut ctx, _) = make_context(fake_device);
992 let mut bss = make_infra_bss(&mut ctx).await;
993
994 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
995
996 bss.handle_mlme_eapol_req(
997 &mut ctx,
998 fidl_mlme::EapolRequest {
999 dst_addr: CLIENT_ADDR.to_array(),
1000 src_addr: BSSID.to_array(),
1001 data: vec![1, 2, 3],
1002 },
1003 )
1004 .expect("expected InfraBss::handle_mlme_eapol_req ok");
1005 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1006 assert_eq!(
1007 &fake_device_state.lock().wlan_queue[0].0[..],
1008 &[
1009 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,
1021 ][..]
1022 );
1023
1024 let confirm = fake_device_state
1025 .lock()
1026 .next_mlme_msg::<fidl_mlme::EapolConfirm>()
1027 .expect("Did not receive valid Eapol Confirm msg");
1028 assert_eq!(confirm.result_code, fidl_mlme::EapolResultCode::Success);
1029 assert_eq!(&confirm.dst_addr, CLIENT_ADDR.as_array());
1030 }
1031
1032 #[fuchsia::test(allow_stalls = false)]
1033 async fn handle_mgmt_frame_auth() {
1034 let (fake_device, fake_device_state) = FakeDevice::new().await;
1035 let (mut ctx, _) = make_context(fake_device);
1036 let mut bss = make_infra_bss(&mut ctx).await;
1037
1038 bss.handle_mgmt_frame(
1039 &mut ctx,
1040 mac::MgmtFrame {
1041 mgmt_hdr: mac::MgmtHdr {
1042 frame_ctrl: mac::FrameControl(0)
1043 .with_frame_type(mac::FrameType::MGMT)
1044 .with_mgmt_subtype(mac::MgmtSubtype::AUTH),
1045 duration: 0,
1046 addr1: (*BSSID).into(),
1047 addr2: *CLIENT_ADDR,
1048 addr3: (*BSSID).into(),
1049 seq_ctrl: mac::SequenceControl(10),
1050 }
1051 .as_bytes_ref(),
1052 ht_ctrl: None,
1053 body: &[
1054 0, 0, 1, 0, 0, 0, ][..],
1059 },
1060 )
1061 .await
1062 .expect("expected OK");
1063
1064 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), true);
1065
1066 let msg = fake_device_state
1067 .lock()
1068 .next_mlme_msg::<fidl_mlme::AuthenticateIndication>()
1069 .expect("expected MLME message");
1070 assert_eq!(
1071 msg,
1072 fidl_mlme::AuthenticateIndication {
1073 peer_sta_address: CLIENT_ADDR.to_array(),
1074 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1075 },
1076 );
1077 }
1078
1079 #[fuchsia::test(allow_stalls = false)]
1080 async fn handle_mgmt_frame_assoc_req() {
1081 let (fake_device, fake_device_state) = FakeDevice::new().await;
1082 let (mut ctx, _) = make_context(fake_device);
1083 let mut bss = make_infra_bss(&mut ctx).await;
1084
1085 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1086 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1087 client
1088 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1089 .await
1090 .expect("expected OK");
1091
1092 bss.handle_mgmt_frame(
1093 &mut ctx,
1094 mac::MgmtFrame {
1095 mgmt_hdr: mac::MgmtHdr {
1096 frame_ctrl: mac::FrameControl(0)
1097 .with_frame_type(mac::FrameType::MGMT)
1098 .with_mgmt_subtype(mac::MgmtSubtype::ASSOC_REQ),
1099 duration: 0,
1100 addr1: (*BSSID).into(),
1101 addr2: *CLIENT_ADDR,
1102 addr3: (*BSSID).into(),
1103 seq_ctrl: mac::SequenceControl(10),
1104 }
1105 .as_bytes_ref(),
1106 ht_ctrl: None,
1107 body: &[
1108 0, 0, 10, 0, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 2, 9, 10, 48, 2, 77, 88, ][..],
1116 },
1117 )
1118 .await
1119 .expect("expected OK");
1120
1121 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), true);
1122
1123 let msg = fake_device_state
1124 .lock()
1125 .next_mlme_msg::<fidl_mlme::AssociateIndication>()
1126 .expect("expected MLME message");
1127 assert_eq!(
1128 msg,
1129 fidl_mlme::AssociateIndication {
1130 peer_sta_address: CLIENT_ADDR.to_array(),
1131 listen_interval: 10,
1132 ssid: Some(Ssid::try_from("coolnet").unwrap().into()),
1133 capability_info: 0,
1134 rates: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
1135 rsne: Some(vec![48, 2, 77, 88]),
1136 },
1137 );
1138 }
1139
1140 #[fuchsia::test(allow_stalls = false)]
1141 async fn handle_mgmt_frame_bad_ds_bits_to_ds() {
1142 let (fake_device, _) = FakeDevice::new().await;
1143 let (mut ctx, _) = make_context(fake_device);
1144 let mut bss = make_infra_bss(&mut ctx).await;
1145
1146 assert_variant!(
1147 bss.handle_mgmt_frame(
1148 &mut ctx,
1149 mac::MgmtFrame {
1150 mgmt_hdr: mac::MgmtHdr {
1151 frame_ctrl: mac::FrameControl(0)
1152 .with_frame_type(mac::FrameType::MGMT)
1153 .with_mgmt_subtype(mac::MgmtSubtype::AUTH)
1154 .with_to_ds(true),
1155 duration: 0,
1156 addr1: (*BSSID).into(),
1157 addr2: *CLIENT_ADDR,
1158 addr3: (*BSSID).into(),
1159 seq_ctrl: mac::SequenceControl(10),
1160 }
1161 .as_bytes_ref(),
1162 ht_ctrl: None,
1163 body: &[
1164 0, 0, 1, 0, 0, 0, ][..],
1169 },
1170 )
1171 .await
1172 .expect_err("expected error"),
1173 Rejection::BadDsBits
1174 );
1175
1176 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), false);
1177 }
1178
1179 #[fuchsia::test(allow_stalls = false)]
1180 async fn handle_mgmt_frame_bad_ds_bits_from_ds() {
1181 let (fake_device, _) = FakeDevice::new().await;
1182 let (mut ctx, _) = make_context(fake_device);
1183 let mut bss = make_infra_bss(&mut ctx).await;
1184
1185 assert_variant!(
1186 bss.handle_mgmt_frame(
1187 &mut ctx,
1188 mac::MgmtFrame {
1189 mgmt_hdr: mac::MgmtHdr {
1190 frame_ctrl: mac::FrameControl(0)
1191 .with_frame_type(mac::FrameType::MGMT)
1192 .with_mgmt_subtype(mac::MgmtSubtype::AUTH)
1193 .with_from_ds(true),
1194 duration: 0,
1195 addr1: (*BSSID).into(),
1196 addr2: *CLIENT_ADDR,
1197 addr3: (*BSSID).into(),
1198 seq_ctrl: mac::SequenceControl(10),
1199 }
1200 .as_bytes_ref(),
1201 ht_ctrl: None,
1202 body: &[
1203 0, 0, 1, 0, 0, 0, ][..],
1208 },
1209 )
1210 .await
1211 .expect_err("expected error"),
1212 Rejection::BadDsBits
1213 );
1214
1215 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), false);
1216 }
1217
1218 #[fuchsia::test(allow_stalls = false)]
1219 async fn handle_mgmt_frame_no_such_client() {
1220 let (fake_device, _) = FakeDevice::new().await;
1221 let (mut ctx, _) = make_context(fake_device);
1222 let mut bss = make_infra_bss(&mut ctx).await;
1223
1224 assert_variant!(
1225 bss.handle_mgmt_frame(
1226 &mut ctx,
1227 mac::MgmtFrame {
1228 mgmt_hdr: mac::MgmtHdr {
1229 frame_ctrl: mac::FrameControl(0)
1230 .with_frame_type(mac::FrameType::MGMT)
1231 .with_mgmt_subtype(mac::MgmtSubtype::DISASSOC),
1232 duration: 0,
1233 addr1: (*BSSID).into(),
1234 addr2: *CLIENT_ADDR,
1235 addr3: (*BSSID).into(),
1236 seq_ctrl: mac::SequenceControl(10),
1237 }
1238 .as_bytes_ref(),
1239 ht_ctrl: None,
1240 body: &[
1241 8, 0, ][..],
1244 },
1245 )
1246 .await
1247 .expect_err("expected error"),
1248 Rejection::Client(_, ClientRejection::NotPermitted)
1249 );
1250
1251 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), false);
1252 }
1253
1254 #[fuchsia::test(allow_stalls = false)]
1255 async fn handle_mgmt_frame_bogus() {
1256 let (fake_device, _) = FakeDevice::new().await;
1257 let (mut ctx, _) = make_context(fake_device);
1258 let mut bss = make_infra_bss(&mut ctx).await;
1259
1260 assert_variant!(
1261 bss.handle_mgmt_frame(
1262 &mut ctx,
1263 mac::MgmtFrame {
1264 mgmt_hdr: mac::MgmtHdr {
1265 frame_ctrl: mac::FrameControl(0)
1266 .with_frame_type(mac::FrameType::MGMT)
1267 .with_mgmt_subtype(mac::MgmtSubtype::AUTH),
1268 duration: 0,
1269 addr1: (*BSSID).into(),
1270 addr2: *CLIENT_ADDR,
1271 addr3: (*BSSID).into(),
1272 seq_ctrl: mac::SequenceControl(10),
1273 }
1274 .as_bytes_ref(),
1275 ht_ctrl: None,
1276 body: &[][..],
1278 },
1279 )
1280 .await
1281 .expect_err("expected error"),
1282 Rejection::Client(_, ClientRejection::ParseFailed)
1283 );
1284
1285 assert_eq!(bss.clients.contains_key(&CLIENT_ADDR), false);
1286 }
1287
1288 #[fuchsia::test(allow_stalls = false)]
1289 async fn handle_data_frame() {
1290 let (fake_device, fake_device_state) = FakeDevice::new().await;
1291 let (mut ctx, _) = make_context(fake_device);
1292 let mut bss = make_infra_bss(&mut ctx).await;
1293
1294 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1295 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1296
1297 client
1299 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1300 .await
1301 .expect("expected OK");
1302 client
1303 .handle_mlme_assoc_resp(
1304 &mut ctx,
1305 false,
1306 1,
1307 mac::CapabilityInfo(0),
1308 fidl_mlme::AssociateResultCode::Success,
1309 1,
1310 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1311 )
1312 .await
1313 .expect("expected OK");
1314
1315 bss.handle_data_frame(
1316 &mut ctx,
1317 mac::DataFrame {
1318 fixed_fields: mac::FixedDataHdrFields {
1319 frame_ctrl: mac::FrameControl(0)
1320 .with_frame_type(mac::FrameType::DATA)
1321 .with_to_ds(true),
1322 duration: 0,
1323 addr1: (*BSSID).into(),
1324 addr2: *CLIENT_ADDR,
1325 addr3: *CLIENT_ADDR2,
1326 seq_ctrl: mac::SequenceControl(10),
1327 }
1328 .as_bytes_ref(),
1329 addr4: None,
1330 qos_ctrl: None,
1331 ht_ctrl: None,
1332 body: &[
1333 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1338 ][..],
1339 },
1340 )
1341 .expect("expected OK");
1342
1343 assert_eq!(fake_device_state.lock().eth_queue.len(), 1);
1344 assert_eq!(
1345 &fake_device_state.lock().eth_queue[0][..],
1346 &[
1347 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 0x12, 0x34, 1, 2, 3, 4, 5,
1352 ][..]
1353 );
1354 }
1355
1356 #[fuchsia::test(allow_stalls = false)]
1357 async fn handle_data_frame_bad_ds_bits() {
1358 let (fake_device, fake_device_state) = FakeDevice::new().await;
1359 let (mut ctx, _) = make_context(fake_device);
1360 let mut bss = make_infra_bss(&mut ctx).await;
1361
1362 assert_variant!(
1363 bss.handle_data_frame(
1364 &mut ctx,
1365 mac::DataFrame {
1366 fixed_fields: mac::FixedDataHdrFields {
1367 frame_ctrl: mac::FrameControl(0)
1368 .with_frame_type(mac::FrameType::DATA)
1369 .with_to_ds(false),
1370 duration: 0,
1371 addr1: (*BSSID).into(),
1372 addr2: *CLIENT_ADDR,
1373 addr3: *CLIENT_ADDR2,
1374 seq_ctrl: mac::SequenceControl(10),
1375 }
1376 .as_bytes_ref(),
1377 addr4: None,
1378 qos_ctrl: None,
1379 ht_ctrl: None,
1380 body: &[
1381 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1386 ][..],
1387 },
1388 )
1389 .expect_err("expected error"),
1390 Rejection::BadDsBits
1391 );
1392
1393 assert_eq!(fake_device_state.lock().eth_queue.len(), 0);
1394 }
1395
1396 #[fuchsia::test(allow_stalls = false)]
1397 async fn handle_client_event() {
1398 let (fake_device, fake_device_state) = FakeDevice::new().await;
1399 let (mut ctx, mut time_stream) = make_context(fake_device);
1400 let mut bss = make_infra_bss(&mut ctx).await;
1401
1402 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1403 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1404
1405 client
1407 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1408 .await
1409 .expect("expected OK");
1410 client
1411 .handle_mlme_assoc_resp(
1412 &mut ctx,
1413 false,
1414 1,
1415 mac::CapabilityInfo(0),
1416 fidl_mlme::AssociateResultCode::Success,
1417 1,
1418 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1419 )
1420 .await
1421 .expect("expected OK");
1422
1423 fake_device_state.lock().wlan_queue.clear();
1424
1425 let _ = time_stream.try_next().unwrap().expect("Should have scheduled a timeout");
1426 bss.handle_timed_event(
1427 &mut ctx,
1428 TimedEvent::ClientEvent(*CLIENT_ADDR, ClientEvent::BssIdleTimeout),
1429 )
1430 .await
1431 .expect("expected OK");
1432
1433 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1435 #[rustfmt::skip]
1436 assert_eq!(&fake_device_state.lock().wlan_queue[0].0[..], &[
1437 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, ][..]);
1447
1448 let msg = fake_device_state
1449 .lock()
1450 .next_mlme_msg::<fidl_mlme::DisassociateIndication>()
1451 .expect("expected MLME message");
1452 assert_eq!(
1453 msg,
1454 fidl_mlme::DisassociateIndication {
1455 peer_sta_address: CLIENT_ADDR.to_array(),
1456 reason_code: fidl_ieee80211::ReasonCode::ReasonInactivity,
1457 locally_initiated: true,
1458 },
1459 );
1460 }
1461
1462 #[fuchsia::test(allow_stalls = false)]
1463 async fn handle_data_frame_no_such_client() {
1464 let (fake_device, fake_device_state) = FakeDevice::new().await;
1465 let (mut ctx, _) = make_context(fake_device);
1466 let mut bss = make_infra_bss(&mut ctx).await;
1467
1468 assert_variant!(
1469 bss.handle_data_frame(
1470 &mut ctx,
1471 mac::DataFrame {
1472 fixed_fields: mac::FixedDataHdrFields {
1473 frame_ctrl: mac::FrameControl(0)
1474 .with_frame_type(mac::FrameType::DATA)
1475 .with_to_ds(true),
1476 duration: 0,
1477 addr1: (*BSSID).into(),
1478 addr2: *CLIENT_ADDR,
1479 addr3: *CLIENT_ADDR2,
1480 seq_ctrl: mac::SequenceControl(10),
1481 }
1482 .as_bytes_ref(),
1483 addr4: None,
1484 qos_ctrl: None,
1485 ht_ctrl: None,
1486 body: &[
1487 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1492 ][..],
1493 },
1494 )
1495 .expect_err("expected error"),
1496 Rejection::Client(_, ClientRejection::NotPermitted)
1497 );
1498
1499 assert_eq!(fake_device_state.lock().eth_queue.len(), 0);
1500
1501 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1502 assert_eq!(
1503 fake_device_state.lock().wlan_queue[0].0,
1504 &[
1505 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, ][..]
1515 );
1516 }
1517
1518 #[fuchsia::test(allow_stalls = false)]
1519 async fn handle_data_frame_client_not_associated() {
1520 let (fake_device, fake_device_state) = FakeDevice::new().await;
1521 let (mut ctx, _) = make_context(fake_device);
1522 let mut bss = make_infra_bss(&mut ctx).await;
1523
1524 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1525 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1526
1527 client
1530 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1531 .await
1532 .expect("expected OK");
1533
1534 fake_device_state.lock().wlan_queue.clear();
1535
1536 assert_variant!(
1537 bss.handle_data_frame(
1538 &mut ctx,
1539 mac::DataFrame {
1540 fixed_fields: mac::FixedDataHdrFields {
1541 frame_ctrl: mac::FrameControl(0)
1542 .with_frame_type(mac::FrameType::DATA)
1543 .with_to_ds(true),
1544 duration: 0,
1545 addr1: (*BSSID).into(),
1546 addr2: *CLIENT_ADDR,
1547 addr3: *CLIENT_ADDR2,
1548 seq_ctrl: mac::SequenceControl(10),
1549 }
1550 .as_bytes_ref(),
1551 addr4: None,
1552 qos_ctrl: None,
1553 ht_ctrl: None,
1554 body: &[
1555 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1560 ][..],
1561 },
1562 )
1563 .expect_err("expected error"),
1564 Rejection::Client(_, ClientRejection::NotPermitted)
1565 );
1566
1567 assert_eq!(fake_device_state.lock().eth_queue.len(), 0);
1568
1569 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1570 assert_eq!(
1571 fake_device_state.lock().wlan_queue[0].0,
1572 &[
1573 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, ][..]
1583 );
1584 }
1585
1586 #[fuchsia::test(allow_stalls = false)]
1587 async fn handle_eth_frame_no_rsn() {
1588 let (fake_device, fake_device_state) = FakeDevice::new().await;
1589 let (mut ctx, _) = make_context(fake_device);
1590 let mut bss = make_infra_bss(&mut ctx).await;
1591 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1592
1593 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1594 client
1595 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1596 .await
1597 .expect("expected OK");
1598 client
1599 .handle_mlme_assoc_resp(
1600 &mut ctx,
1601 false,
1602 1,
1603 mac::CapabilityInfo(0),
1604 fidl_mlme::AssociateResultCode::Success,
1605 1,
1606 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1607 )
1608 .await
1609 .expect("expected OK");
1610 fake_device_state.lock().wlan_queue.clear();
1611
1612 bss.handle_eth_frame(
1613 &mut ctx,
1614 EthernetIIHdr {
1615 da: *CLIENT_ADDR,
1616 sa: *CLIENT_ADDR2,
1617 ether_type: BigEndianU16::from_native(0x1234),
1618 },
1619 &[1, 2, 3, 4, 5][..],
1620 0.into(),
1621 )
1622 .expect("expected OK");
1623
1624 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1625 assert_eq!(
1626 &fake_device_state.lock().wlan_queue[0].0[..],
1627 &[
1628 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,
1640 ][..]
1641 );
1642 }
1643
1644 #[fuchsia::test(allow_stalls = false)]
1645 async fn handle_eth_frame_no_client() {
1646 let (fake_device, fake_device_state) = FakeDevice::new().await;
1647 let (mut ctx, _) = make_context(fake_device);
1648 let mut bss = make_infra_bss(&mut ctx).await;
1649
1650 assert_variant!(
1651 bss.handle_eth_frame(
1652 &mut ctx,
1653 EthernetIIHdr {
1654 da: *CLIENT_ADDR,
1655 sa: *CLIENT_ADDR2,
1656 ether_type: BigEndianU16::from_native(0x1234)
1657 },
1658 &[1, 2, 3, 4, 5][..],
1659 0.into(),
1660 )
1661 .expect_err("expected error"),
1662 Rejection::Client(_, ClientRejection::NotAssociated)
1663 );
1664
1665 assert_eq!(fake_device_state.lock().wlan_queue.len(), 0);
1666 }
1667
1668 #[fuchsia::test(allow_stalls = false)]
1669 async fn handle_eth_frame_is_rsn_eapol_controlled_port_closed() {
1670 let (fake_device, fake_device_state) = FakeDevice::new().await;
1671 let (mut ctx, _) = make_context(fake_device);
1672 let mut bss = make_protected_infra_bss(&mut ctx).await;
1673 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1674
1675 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1676 client
1677 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1678 .await
1679 .expect("expected OK");
1680 client
1681 .handle_mlme_assoc_resp(
1682 &mut ctx,
1683 true,
1684 1,
1685 mac::CapabilityInfo(0),
1686 fidl_mlme::AssociateResultCode::Success,
1687 1,
1688 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1689 )
1690 .await
1691 .expect("expected OK");
1692 fake_device_state.lock().wlan_queue.clear();
1693
1694 assert_variant!(
1695 bss.handle_eth_frame(
1696 &mut ctx,
1697 EthernetIIHdr {
1698 da: *CLIENT_ADDR,
1699 sa: *CLIENT_ADDR2,
1700 ether_type: BigEndianU16::from_native(0x1234)
1701 },
1702 &[1, 2, 3, 4, 5][..],
1703 0.into(),
1704 )
1705 .expect_err("expected error"),
1706 Rejection::Client(_, ClientRejection::ControlledPortClosed)
1707 );
1708 }
1709
1710 #[fuchsia::test(allow_stalls = false)]
1711 async fn handle_eth_frame_is_rsn_eapol_controlled_port_open() {
1712 let (fake_device, fake_device_state) = FakeDevice::new().await;
1713 let (mut ctx, _) = make_context(fake_device);
1714 let mut bss = make_protected_infra_bss(&mut ctx).await;
1715 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1716
1717 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1718 client
1719 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1720 .await
1721 .expect("expected OK");
1722 client
1723 .handle_mlme_assoc_resp(
1724 &mut ctx,
1725 true,
1726 1,
1727 mac::CapabilityInfo(0),
1728 fidl_mlme::AssociateResultCode::Success,
1729 1,
1730 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1731 )
1732 .await
1733 .expect("expected OK");
1734 fake_device_state.lock().wlan_queue.clear();
1735
1736 client
1737 .handle_mlme_set_controlled_port_req(fidl_mlme::ControlledPortState::Open)
1738 .expect("expected OK");
1739
1740 bss.handle_eth_frame(
1741 &mut ctx,
1742 EthernetIIHdr {
1743 da: *CLIENT_ADDR,
1744 sa: *CLIENT_ADDR2,
1745 ether_type: BigEndianU16::from_native(0x1234),
1746 },
1747 &[1, 2, 3, 4, 5][..],
1748 0.into(),
1749 )
1750 .expect("expected OK");
1751
1752 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1753 assert_eq!(
1754 &fake_device_state.lock().wlan_queue[0].0[..],
1755 &[
1756 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,
1768 ][..]
1769 );
1770 }
1771
1772 #[test_case(false; "Controlled port closed")]
1773 #[test_case(true; "Controlled port open")]
1774 #[fuchsia::test(allow_stalls = false)]
1775 async fn handle_data_frame_is_rsn_eapol(controlled_port_open: bool) {
1776 let (fake_device, fake_device_state) = FakeDevice::new().await;
1777 let (mut ctx, _) = make_context(fake_device);
1778 let mut bss = make_protected_infra_bss(&mut ctx).await;
1779 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1780
1781 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1782 client
1783 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1784 .await
1785 .expect("expected OK");
1786 client
1787 .handle_mlme_assoc_resp(
1788 &mut ctx,
1789 true,
1790 1,
1791 mac::CapabilityInfo(0),
1792 fidl_mlme::AssociateResultCode::Success,
1793 1,
1794 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
1795 )
1796 .await
1797 .expect("expected OK");
1798 fake_device_state.lock().wlan_queue.clear();
1799
1800 if controlled_port_open {
1801 client
1802 .handle_mlme_set_controlled_port_req(fidl_mlme::ControlledPortState::Open)
1803 .expect("expected OK");
1804 }
1805
1806 bss.handle_data_frame(
1807 &mut ctx,
1808 mac::DataFrame {
1809 fixed_fields: mac::FixedDataHdrFields {
1810 frame_ctrl: mac::FrameControl(0)
1811 .with_frame_type(mac::FrameType::DATA)
1812 .with_to_ds(true),
1813 duration: 0,
1814 addr1: (*BSSID).into(),
1815 addr2: *CLIENT_ADDR,
1816 addr3: *CLIENT_ADDR2,
1817 seq_ctrl: mac::SequenceControl(10),
1818 }
1819 .as_bytes_ref(),
1820 addr4: None,
1821 qos_ctrl: None,
1822 ht_ctrl: None,
1823 body: &[
1824 7, 7, 7, 8, 8, 8, 0x12, 0x34, 1, 2, 3, 4, 5,
1829 ][..],
1830 },
1831 )
1832 .expect("expected OK");
1833
1834 if controlled_port_open {
1835 assert_eq!(fake_device_state.lock().eth_queue.len(), 1);
1836 } else {
1837 assert!(fake_device_state.lock().eth_queue.is_empty());
1838 }
1839 }
1840
1841 async fn authenticate_client(
1842 fake_device_state: Arc<Mutex<FakeDeviceState>>,
1843 ctx: &mut Context<FakeDevice>,
1844 bss: &mut InfraBss,
1845 client_addr: MacAddr,
1846 ) {
1847 bss.handle_mgmt_frame(
1848 ctx,
1849 mac::MgmtFrame {
1850 mgmt_hdr: mac::MgmtHdr {
1851 frame_ctrl: mac::FrameControl(0)
1852 .with_frame_type(mac::FrameType::MGMT)
1853 .with_mgmt_subtype(mac::MgmtSubtype::AUTH),
1854 duration: 0,
1855 addr1: (*BSSID).into(),
1856 addr2: client_addr,
1857 addr3: (*BSSID).into(),
1858 seq_ctrl: mac::SequenceControl(10),
1859 }
1860 .as_bytes_ref(),
1861 ht_ctrl: None,
1862 body: &[
1863 0, 0, 1, 0, 0, 0, ][..],
1868 },
1869 )
1870 .await
1871 .expect("failed to handle auth req frame");
1872
1873 fake_device_state
1874 .lock()
1875 .next_mlme_msg::<fidl_mlme::AuthenticateIndication>()
1876 .expect("expected auth indication");
1877 bss.handle_mlme_auth_resp(
1878 ctx,
1879 fidl_mlme::AuthenticateResponse {
1880 peer_sta_address: client_addr.to_array(),
1881 result_code: fidl_mlme::AuthenticateResultCode::Success,
1882 },
1883 )
1884 .await
1885 .expect("failed to handle auth resp");
1886 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1887 fake_device_state.lock().wlan_queue.clear();
1888 }
1889
1890 async fn associate_client(
1891 fake_device_state: Arc<Mutex<FakeDeviceState>>,
1892 ctx: &mut Context<FakeDevice>,
1893 bss: &mut InfraBss,
1894 client_addr: MacAddr,
1895 association_id: u16,
1896 ) {
1897 bss.handle_mgmt_frame(
1898 ctx,
1899 mac::MgmtFrame {
1900 mgmt_hdr: mac::MgmtHdr {
1901 frame_ctrl: mac::FrameControl(0)
1902 .with_frame_type(mac::FrameType::MGMT)
1903 .with_mgmt_subtype(mac::MgmtSubtype::ASSOC_REQ),
1904 duration: 0,
1905 addr1: (*BSSID).into(),
1906 addr2: client_addr,
1907 addr3: (*BSSID).into(),
1908 seq_ctrl: mac::SequenceControl(10),
1909 }
1910 .as_bytes_ref(),
1911 ht_ctrl: None,
1912 body: &[
1913 0, 0, 10, 0, 1, 8, 1, 2, 3, 4, 5, 6, 7, 8, 50, 2, 9, 10, 48, 2, 77, 88, ][..],
1921 },
1922 )
1923 .await
1924 .expect("expected OK");
1925 let msg = fake_device_state
1926 .lock()
1927 .next_mlme_msg::<fidl_mlme::AssociateIndication>()
1928 .expect("expected assoc indication");
1929 bss.handle_mlme_assoc_resp(
1930 ctx,
1931 fidl_mlme::AssociateResponse {
1932 peer_sta_address: client_addr.to_array(),
1933 result_code: fidl_mlme::AssociateResultCode::Success,
1934 association_id,
1935 capability_info: msg.capability_info,
1936 rates: msg.rates,
1937 },
1938 )
1939 .await
1940 .expect("failed to handle assoc resp");
1941 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
1942 fake_device_state.lock().wlan_queue.clear();
1943 }
1944
1945 fn send_eth_frame_from_ds_to_client(
1946 ctx: &mut Context<FakeDevice>,
1947 bss: &mut InfraBss,
1948 client_addr: MacAddr,
1949 ) {
1950 bss.handle_eth_frame(
1951 ctx,
1952 EthernetIIHdr {
1953 da: client_addr,
1954 sa: *REMOTE_ADDR,
1955 ether_type: BigEndianU16::from_native(0x1234),
1956 },
1957 &[1, 2, 3, 4, 5][..],
1958 0.into(),
1959 )
1960 .expect("expected OK");
1961 }
1962
1963 #[fuchsia::test(allow_stalls = false)]
1964 async fn handle_multiple_complete_associations() {
1965 let (fake_device, fake_device_state) = FakeDevice::new().await;
1966 let (mut ctx, _) = make_context(fake_device);
1967 let mut bss = make_infra_bss(&mut ctx).await;
1968
1969 authenticate_client(fake_device_state.clone(), &mut ctx, &mut bss, *CLIENT_ADDR).await;
1970 authenticate_client(fake_device_state.clone(), &mut ctx, &mut bss, *CLIENT_ADDR2).await;
1971
1972 associate_client(fake_device_state.clone(), &mut ctx, &mut bss, *CLIENT_ADDR, 1).await;
1973 associate_client(fake_device_state.clone(), &mut ctx, &mut bss, *CLIENT_ADDR2, 2).await;
1974
1975 assert!(bss.clients.contains_key(&CLIENT_ADDR));
1976 assert!(bss.clients.contains_key(&CLIENT_ADDR2));
1977
1978 send_eth_frame_from_ds_to_client(&mut ctx, &mut bss, *CLIENT_ADDR);
1979 send_eth_frame_from_ds_to_client(&mut ctx, &mut bss, *CLIENT_ADDR2);
1980
1981 assert_eq!(fake_device_state.lock().wlan_queue.len(), 2);
1982 }
1983
1984 #[fuchsia::test(allow_stalls = false)]
1985 async fn handle_ps_poll() {
1986 let (fake_device, fake_device_state) = FakeDevice::new().await;
1987 let (mut ctx, _) = make_context(fake_device);
1988 let mut bss = make_infra_bss(&mut ctx).await;
1989 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
1990
1991 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
1992 client
1993 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
1994 .await
1995 .expect("expected OK");
1996 client
1997 .handle_mlme_assoc_resp(
1998 &mut ctx,
1999 false,
2000 1,
2001 mac::CapabilityInfo(0),
2002 fidl_mlme::AssociateResultCode::Success,
2003 1,
2004 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
2005 )
2006 .await
2007 .expect("expected OK");
2008 client.set_power_state(&mut ctx, mac::PowerState::DOZE).expect("expected doze ok");
2009 fake_device_state.lock().wlan_queue.clear();
2010
2011 bss.handle_eth_frame(
2012 &mut ctx,
2013 EthernetIIHdr {
2014 da: *CLIENT_ADDR,
2015 sa: *CLIENT_ADDR2,
2016 ether_type: BigEndianU16::from_native(0x1234),
2017 },
2018 &[1, 2, 3, 4, 5][..],
2019 0.into(),
2020 )
2021 .expect("expected OK");
2022 assert_eq!(fake_device_state.lock().wlan_queue.len(), 0);
2023
2024 bss.handle_ctrl_frame(
2025 &mut ctx,
2026 mac::CtrlFrame {
2027 frame_ctrl: mac::FrameControl(0)
2028 .with_frame_type(mac::FrameType::CTRL)
2029 .with_ctrl_subtype(mac::CtrlSubtype::PS_POLL),
2030 body: &[
2031 0b00000001, 0b11000000, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, ][..],
2035 },
2036 )
2037 .expect("expected OK");
2038 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
2039 assert_eq!(
2040 &fake_device_state.lock().wlan_queue[0].0[..],
2041 &[
2042 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,
2054 ][..]
2055 );
2056 }
2057
2058 #[fuchsia::test(allow_stalls = false)]
2059 async fn handle_mlme_setkeys_req() {
2060 let (fake_device, fake_device_state) = FakeDevice::new().await;
2061 let (mut ctx, _) = make_context(fake_device);
2062 let mut bss = make_protected_infra_bss(&mut ctx).await;
2063 bss.handle_mlme_setkeys_req(
2064 &mut ctx,
2065 vec![fidl_mlme::SetKeyDescriptor {
2066 cipher_suite_oui: [1, 2, 3],
2067 cipher_suite_type: fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
2068 key_type: fidl_mlme::KeyType::Pairwise,
2069 address: [5; 6].into(),
2070 key_id: 6,
2071 key: vec![1, 2, 3, 4, 5, 6, 7],
2072 rsc: 8,
2073 }],
2074 )
2075 .await
2076 .expect("expected InfraBss::handle_mlme_setkeys_req OK");
2077 assert_eq!(
2078 fake_device_state.lock().keys,
2079 vec![fidl_softmac::WlanKeyConfiguration {
2080 protection: Some(fidl_softmac::WlanProtection::RxTx),
2081 cipher_oui: Some([1, 2, 3]),
2082 cipher_type: Some(4),
2083 key_type: Some(fidl_ieee80211::KeyType::Pairwise),
2084 peer_addr: Some([5; 6]),
2085 key_idx: Some(6),
2086 key: Some(vec![1, 2, 3, 4, 5, 6, 7]),
2087 rsc: Some(8),
2088 ..Default::default()
2089 }]
2090 );
2091 }
2092
2093 #[fuchsia::test(allow_stalls = false)]
2094 async fn handle_mlme_setkeys_req_no_rsne() {
2095 let (fake_device, fake_device_state) = FakeDevice::new().await;
2096 let (mut ctx, _) = make_context(fake_device);
2097 let mut bss = make_infra_bss(&mut ctx).await;
2098 assert_variant!(
2099 bss.handle_mlme_setkeys_req(
2100 &mut ctx,
2101 vec![fidl_mlme::SetKeyDescriptor {
2102 cipher_suite_oui: [1, 2, 3],
2103 cipher_suite_type:
2104 fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(4),
2105 key_type: fidl_mlme::KeyType::Pairwise,
2106 address: [5; 6],
2107 key_id: 6,
2108 key: vec![1, 2, 3, 4, 5, 6, 7],
2109 rsc: 8,
2110 }]
2111 )
2112 .await
2113 .expect_err("expected InfraBss::handle_mlme_setkeys_req error"),
2114 Error::Status(_, zx::Status::BAD_STATE)
2115 );
2116 assert!(fake_device_state.lock().keys.is_empty());
2117 }
2118
2119 #[fuchsia::test(allow_stalls = false)]
2120 async fn handle_probe_req() {
2121 let (fake_device, fake_device_state) = FakeDevice::new().await;
2122 let (mut ctx, _) = make_context(fake_device);
2123 let mut bss = InfraBss::new(
2124 &mut ctx,
2125 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2126 TimeUnit::DEFAULT_BEACON_INTERVAL,
2127 2,
2128 mac::CapabilityInfo(33),
2129 vec![248],
2130 1,
2131 Some(vec![48, 2, 77, 88]),
2132 )
2133 .await
2134 .expect("expected InfraBss::new ok");
2135
2136 bss.handle_probe_req(&mut ctx, *CLIENT_ADDR)
2137 .expect("expected InfraBss::handle_probe_req ok");
2138 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
2139 assert_eq!(
2140 &fake_device_state.lock().wlan_queue[0].0[..],
2141 &[
2142 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, ][..]
2159 );
2160 }
2161
2162 #[fuchsia::test(allow_stalls = false)]
2163 async fn handle_probe_req_has_offload() {
2164 let (fake_device, _fake_device_state) = FakeDevice::new_with_config(
2165 FakeDeviceConfig::default().with_mock_probe_response_offload(
2166 fidl_common::ProbeResponseOffloadExtension { supported: true },
2167 ),
2168 )
2169 .await;
2170
2171 let (mut ctx, _) = make_context(fake_device);
2172 let mut bss = InfraBss::new(
2173 &mut ctx,
2174 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2175 TimeUnit::DEFAULT_BEACON_INTERVAL,
2176 2,
2177 CapabilityInfo(33),
2178 vec![0b11111000],
2179 1,
2180 Some(vec![48, 2, 77, 88]),
2181 )
2182 .await
2183 .expect("expected InfraBss::new ok");
2184
2185 bss.handle_mgmt_frame(
2186 &mut ctx,
2187 mac::MgmtFrame {
2188 mgmt_hdr: mac::MgmtHdr {
2189 frame_ctrl: mac::FrameControl(0)
2190 .with_frame_type(mac::FrameType::MGMT)
2191 .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
2192 duration: 0,
2193 addr1: (*BSSID).into(),
2194 addr2: *CLIENT_ADDR,
2195 addr3: (*BSSID).into(),
2196 seq_ctrl: mac::SequenceControl(10),
2197 }
2198 .as_bytes_ref(),
2199 ht_ctrl: None,
2200 body: &[][..],
2201 },
2202 )
2203 .await
2204 .expect_err("expected InfraBss::handle_mgmt_frame error");
2205 }
2206
2207 #[fuchsia::test(allow_stalls = false)]
2208 async fn handle_probe_req_wildcard_ssid() {
2209 let (fake_device, fake_device_state) = FakeDevice::new().await;
2210 let (mut ctx, _) = make_context(fake_device);
2211 let mut bss = InfraBss::new(
2212 &mut ctx,
2213 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2214 TimeUnit::DEFAULT_BEACON_INTERVAL,
2215 2,
2216 CapabilityInfo(33),
2217 vec![0b11111000],
2218 1,
2219 Some(vec![48, 2, 77, 88]),
2220 )
2221 .await
2222 .expect("expected InfraBss::new ok");
2223
2224 bss.handle_mgmt_frame(
2225 &mut ctx,
2226 mac::MgmtFrame {
2227 mgmt_hdr: mac::MgmtHdr {
2228 frame_ctrl: mac::FrameControl(0)
2229 .with_frame_type(mac::FrameType::MGMT)
2230 .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
2231 duration: 0,
2232 addr1: (*BSSID).into(),
2233 addr2: *CLIENT_ADDR,
2234 addr3: (*BSSID).into(),
2235 seq_ctrl: mac::SequenceControl(10),
2236 }
2237 .as_bytes_ref(),
2238 ht_ctrl: None,
2239 body: &[
2240 0, 0, ][..],
2242 },
2243 )
2244 .await
2245 .expect("expected InfraBss::handle_mgmt_frame ok");
2246
2247 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
2248 assert_eq!(
2249 &fake_device_state.lock().wlan_queue[0].0[..],
2250 &[
2251 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, ][..]
2268 );
2269 }
2270
2271 #[fuchsia::test(allow_stalls = false)]
2272 async fn handle_probe_req_matching_ssid() {
2273 let (fake_device, fake_device_state) = FakeDevice::new().await;
2274 let (mut ctx, _) = make_context(fake_device);
2275 let mut bss = InfraBss::new(
2276 &mut ctx,
2277 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2278 TimeUnit::DEFAULT_BEACON_INTERVAL,
2279 2,
2280 CapabilityInfo(33),
2281 vec![0b11111000],
2282 1,
2283 Some(vec![48, 2, 77, 88]),
2284 )
2285 .await
2286 .expect("expected InfraBss::new ok");
2287
2288 bss.handle_mgmt_frame(
2289 &mut ctx,
2290 mac::MgmtFrame {
2291 mgmt_hdr: mac::MgmtHdr {
2292 frame_ctrl: mac::FrameControl(0)
2293 .with_frame_type(mac::FrameType::MGMT)
2294 .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
2295 duration: 0,
2296 addr1: (*BSSID).into(),
2297 addr2: *CLIENT_ADDR,
2298 addr3: (*BSSID).into(),
2299 seq_ctrl: mac::SequenceControl(10),
2300 }
2301 .as_bytes_ref(),
2302 ht_ctrl: None,
2303 body: &[0, 5, 1, 2, 3, 4, 5][..],
2304 },
2305 )
2306 .await
2307 .expect("expected InfraBss::handle_mgmt_frame ok");
2308
2309 assert_eq!(fake_device_state.lock().wlan_queue.len(), 1);
2310 assert_eq!(
2311 &fake_device_state.lock().wlan_queue[0].0[..],
2312 &[
2313 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, ][..]
2330 );
2331 }
2332
2333 #[fuchsia::test(allow_stalls = false)]
2334 async fn handle_probe_req_mismatching_ssid() {
2335 let (fake_device, _) = FakeDevice::new().await;
2336 let (mut ctx, _) = make_context(fake_device);
2337 let mut bss = InfraBss::new(
2338 &mut ctx,
2339 Ssid::try_from([1, 2, 3, 4, 5]).unwrap(),
2340 TimeUnit::DEFAULT_BEACON_INTERVAL,
2341 2,
2342 CapabilityInfo(33),
2343 vec![0b11111000],
2344 1,
2345 Some(vec![48, 2, 77, 88]),
2346 )
2347 .await
2348 .expect("expected InfraBss::new ok");
2349
2350 assert_variant!(
2351 bss.handle_mgmt_frame(
2352 &mut ctx,
2353 mac::MgmtFrame {
2354 mgmt_hdr: mac::MgmtHdr {
2355 frame_ctrl: mac::FrameControl(0)
2356 .with_frame_type(mac::FrameType::MGMT)
2357 .with_mgmt_subtype(mac::MgmtSubtype::PROBE_REQ),
2358 duration: 0,
2359 addr1: (*BSSID).into(),
2360 addr2: *CLIENT_ADDR,
2361 addr3: (*BSSID).into(),
2362 seq_ctrl: mac::SequenceControl(10),
2363 }
2364 .as_bytes_ref(),
2365 ht_ctrl: None,
2366 body: &[0, 5, 1, 2, 3, 4, 6][..],
2367 },
2368 )
2369 .await
2370 .expect_err("expected InfraBss::handle_mgmt_frame error"),
2371 Rejection::OtherBss
2372 );
2373 }
2374
2375 #[fuchsia::test(allow_stalls = false)]
2376 async fn make_tim() {
2377 let (fake_device, _) = FakeDevice::new().await;
2378 let (mut ctx, _) = make_context(fake_device);
2379 let mut bss = make_infra_bss(&mut ctx).await;
2380 bss.clients.insert(*CLIENT_ADDR, RemoteClient::new(*CLIENT_ADDR));
2381
2382 let client = bss.clients.get_mut(&CLIENT_ADDR).unwrap();
2383 client
2384 .handle_mlme_auth_resp(&mut ctx, fidl_mlme::AuthenticateResultCode::Success)
2385 .await
2386 .expect("expected OK");
2387 client
2388 .handle_mlme_assoc_resp(
2389 &mut ctx,
2390 false,
2391 1,
2392 mac::CapabilityInfo(0),
2393 fidl_mlme::AssociateResultCode::Success,
2394 1,
2395 &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10][..],
2396 )
2397 .await
2398 .expect("expected OK");
2399 client.set_power_state(&mut ctx, mac::PowerState::DOZE).expect("expected doze OK");
2400
2401 bss.handle_eth_frame(
2402 &mut ctx,
2403 EthernetIIHdr {
2404 da: *CLIENT_ADDR,
2405 sa: *CLIENT_ADDR2,
2406 ether_type: BigEndianU16::from_native(0x1234),
2407 },
2408 &[1, 2, 3, 4, 5][..],
2409 0.into(),
2410 )
2411 .expect("expected OK");
2412
2413 let tim = bss.make_tim();
2414 let (pvb_offset, pvb_bitmap) = tim.make_partial_virtual_bitmap();
2415 assert_eq!(pvb_offset, 0);
2416 assert_eq!(pvb_bitmap, &[0b00000010][..]);
2417 }
2418
2419 #[fuchsia::test(allow_stalls = false)]
2420 async fn make_tim_empty() {
2421 let (fake_device, _) = FakeDevice::new().await;
2422 let (mut ctx, _) = make_context(fake_device);
2423 let bss = make_infra_bss(&mut ctx).await;
2424
2425 let tim = bss.make_tim();
2426 let (pvb_offset, pvb_bitmap) = tim.make_partial_virtual_bitmap();
2427 assert_eq!(pvb_offset, 0);
2428 assert_eq!(pvb_bitmap, &[0b00000000][..]);
2429 }
2430}