1use crate::convert::{fullmac_to_mlme, mlme_to_fullmac};
6use crate::device::DeviceOps;
7use crate::wlan_fullmac_impl_ifc_request_handler::serve_wlan_fullmac_impl_ifc_request_handler;
8use crate::{DriverState, FullmacDriverEvent, FullmacDriverEventSink};
9use anyhow::{Context, bail};
10use futures::channel::{mpsc, oneshot};
11use futures::{Future, StreamExt, select};
12use log::{error, info};
13use std::pin::Pin;
14use {
15 fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_fullmac as fidl_fullmac,
16 fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211, fidl_fuchsia_wlan_mlme as fidl_mlme,
17 fuchsia_async as fasync,
18};
19
20pub(crate) fn create_mlme_main_loop<D: DeviceOps>(
28 device: D,
29 mlme_request_stream: wlan_sme::MlmeStream,
30 mlme_event_sink: wlan_sme::MlmeEventSink,
31 driver_event_stream: mpsc::UnboundedReceiver<FullmacDriverEvent>,
32 driver_event_sink: FullmacDriverEventSink,
33 fullmac_ifc_request_stream: fidl_fullmac::WlanFullmacImplIfcRequestStream,
34) -> Pin<Box<impl Future<Output = anyhow::Result<()>>>> {
35 let main_loop = MlmeMainLoop {
36 device,
37 mlme_request_stream,
38 mlme_event_sink,
39 driver_event_stream,
40 is_bss_protected: false,
41 device_link_state: fidl_mlme::ControlledPortState::Closed,
42 };
43
44 Box::pin(main_loop.serve(fullmac_ifc_request_stream, driver_event_sink))
45}
46
47struct MlmeMainLoop<D: DeviceOps> {
48 device: D,
49 mlme_request_stream: wlan_sme::MlmeStream,
50 mlme_event_sink: wlan_sme::MlmeEventSink,
51 driver_event_stream: mpsc::UnboundedReceiver<FullmacDriverEvent>,
52 is_bss_protected: bool,
53 device_link_state: fidl_mlme::ControlledPortState,
54}
55
56impl<D: DeviceOps> MlmeMainLoop<D> {
57 async fn serve(
70 mut self,
71 fullmac_ifc_request_stream: fidl_fullmac::WlanFullmacImplIfcRequestStream,
72 driver_event_sink: FullmacDriverEventSink,
73 ) -> anyhow::Result<()> {
74 let mac_role = self
75 .device
76 .query_device_info()?
77 .role
78 .context("Vendor driver query response missing MAC role")?;
79
80 let (ifc_server_stop_sender, mut ifc_server_stop_receiver) = oneshot::channel::<()>();
83 let _fullmac_ifc_server_task = fasync::Task::spawn(async move {
84 serve_wlan_fullmac_impl_ifc_request_handler(
85 fullmac_ifc_request_stream,
86 driver_event_sink,
87 )
88 .await;
89 info!("WlanFullmacImplIfc server stopped");
90
91 let _ = ifc_server_stop_sender.send(());
95 });
96
97 loop {
98 select! {
99 mlme_request = self.mlme_request_stream.next() => match mlme_request {
100 Some(req) => {
101 if let Err(e) = self.handle_mlme_request(req) {
102 error!("Failed to handle MLME req: {}", e);
103 }
104 },
105 None => bail!("MLME request stream terminated unexpectedly."),
106 },
107 driver_event = self.driver_event_stream.next() => match driver_event {
108 Some(event) => {
109 match self.handle_driver_event(event, &mac_role) {
110 Ok(DriverState::Running) => {},
111 Ok(DriverState::Stopping) => return Ok(()),
112 Err(e) => error!("Failed to handle driver event: {}", e),
113 }
114 },
115 None => bail!("Driver event stream terminated unexpectedly."),
116 },
117 ifc_stop = ifc_server_stop_receiver => match ifc_stop {
118 Ok(()) => bail!("WlanFullmacImplIfc request stream terminated unexpectedly."),
119 Err(e) => bail!("WlanFullmacImplIfc server task dropped stop sender unexpectedly. {}", e),
120 },
121 }
122 }
123 }
124
125 fn handle_mlme_request(&mut self, req: wlan_sme::MlmeRequest) -> anyhow::Result<()> {
126 use wlan_sme::MlmeRequest::*;
127 match req {
128 Scan(req) => self.handle_mlme_scan_request(req)?,
129 Connect(req) => {
130 self.set_link_state(fidl_mlme::ControlledPortState::Closed)?;
131 self.is_bss_protected = !req.security_ie.is_empty();
132 self.device.connect(mlme_to_fullmac::convert_connect_request(req))?;
133 }
134 Reconnect(req) => {
135 self.device.reconnect(mlme_to_fullmac::convert_reconnect_request(req))?;
136 }
137 Roam(req) => {
138 self.set_link_state(fidl_mlme::ControlledPortState::Closed)?;
139 self.device.roam(mlme_to_fullmac::convert_roam_request(req))?;
140 }
141 AuthResponse(resp) => {
142 self.device.auth_resp(mlme_to_fullmac::convert_authenticate_response(resp))?;
143 }
144 Deauthenticate(req) => {
145 self.set_link_state(fidl_mlme::ControlledPortState::Closed)?;
146 self.device.deauth(mlme_to_fullmac::convert_deauthenticate_request(req))?;
147 }
148 AssocResponse(resp) => {
149 self.device.assoc_resp(mlme_to_fullmac::convert_associate_response(resp))?;
150 }
151 Disassociate(req) => {
152 self.set_link_state(fidl_mlme::ControlledPortState::Closed)?;
153 self.device.disassoc(mlme_to_fullmac::convert_disassociate_request(req))?;
154 }
155 Start(req) => {
156 self.device.start_bss(mlme_to_fullmac::convert_start_bss_request(req)?)?
157 }
158 Stop(req) => self.device.stop_bss(mlme_to_fullmac::convert_stop_bss_request(req)?)?,
159 SetKeys(req) => self.handle_mlme_set_keys_request(req)?,
160 Eapol(req) => self.device.eapol_tx(mlme_to_fullmac::convert_eapol_request(req))?,
161 SetCtrlPort(req) => self.set_link_state(req.state)?,
162 QueryDeviceInfo(responder) => {
163 let device_info =
164 fullmac_to_mlme::convert_device_info(self.device.query_device_info()?)?;
165 responder.respond(device_info);
166 }
167 QueryMacSublayerSupport(_) => info!("QueryMacSublayerSupport is unsupported"),
168 QuerySecuritySupport(responder) => {
169 responder.respond(self.device.query_security_support()?)
170 }
171 QuerySpectrumManagementSupport(responder) => {
172 responder.respond(self.device.query_spectrum_management_support()?)
173 }
174 QueryTelemetrySupport(responder) => {
175 responder.respond(self.device.query_telemetry_support()?)
176 }
177 GetIfaceStats(responder) => responder.respond(self.device.get_iface_stats()?),
178 GetIfaceHistogramStats(responder) => {
179 responder.respond(self.device.get_iface_histogram_stats()?)
180 }
181 GetSignalReport(responder) => responder.respond(self.device.get_signal_report()?),
182 GetMinstrelStats(_, _) => info!("GetMinstrelStats is unsupported"),
183 ListMinstrelPeers(_) => info!("ListMinstrelPeers is unsupported"),
184 SaeHandshakeResp(resp) => self
185 .device
186 .sae_handshake_resp(mlme_to_fullmac::convert_sae_handshake_response(resp))?,
187 SaeFrameTx(frame) => {
188 self.device.sae_frame_tx(mlme_to_fullmac::convert_sae_frame(frame))?
189 }
190 WmmStatusReq => self.device.wmm_status_req()?,
191 FinalizeAssociation(..) => info!("FinalizeAssociation is unsupported"),
192 SetMacAddress(mac_addr, responder) => {
193 responder.respond(self.device.set_mac_address(
194 fidl_fullmac::WlanFullmacImplSetMacAddressRequest { mac_addr },
195 )?)
196 }
197 };
198 Ok(())
199 }
200
201 fn handle_mlme_scan_request(&self, req: fidl_mlme::ScanRequest) -> anyhow::Result<()> {
202 if req.channel_list.is_empty() {
203 let end = fidl_mlme::ScanEnd {
204 txn_id: req.txn_id,
205 code: fidl_mlme::ScanResultCode::InvalidArgs,
206 };
207 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::OnScanEnd { end });
208 } else {
209 self.device.start_scan(mlme_to_fullmac::convert_scan_request(req)?)?;
210 }
211 Ok(())
212 }
213
214 fn handle_mlme_set_keys_request(&self, req: fidl_mlme::SetKeysRequest) -> anyhow::Result<()> {
215 let fullmac_req = mlme_to_fullmac::convert_set_keys_request(&req)?;
216 let fullmac_resp = self.device.set_keys(fullmac_req)?;
217 let mlme_resp = fullmac_to_mlme::convert_set_keys_resp(fullmac_resp, &req)?;
218 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::SetKeysConf { conf: mlme_resp });
219 Ok(())
220 }
221
222 fn handle_driver_event(
223 &mut self,
224 event: FullmacDriverEvent,
225 mac_role: &fidl_common::WlanMacRole,
226 ) -> anyhow::Result<DriverState> {
227 match event {
228 FullmacDriverEvent::Stop => return Ok(DriverState::Stopping),
229 FullmacDriverEvent::OnScanResult { result } => {
230 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::OnScanResult { result });
231 }
232 FullmacDriverEvent::OnScanEnd { end } => {
233 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::OnScanEnd { end });
234 }
235 FullmacDriverEvent::ConnectConf { resp } => {
236 if !self.is_bss_protected && resp.result_code == fidl_ieee80211::StatusCode::Success
241 {
242 self.set_link_state(fidl_mlme::ControlledPortState::Open)?;
243 }
244 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::ConnectConf { resp });
245 }
246 FullmacDriverEvent::RoamConf { conf } => {
247 if *mac_role == fidl_common::WlanMacRole::Client {
248 if !self.is_bss_protected
250 && conf.status_code == fidl_ieee80211::StatusCode::Success
251 {
252 self.set_link_state(fidl_mlme::ControlledPortState::Open)?;
253 }
254 }
255 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::RoamConf { conf });
256 }
257 FullmacDriverEvent::RoamStartInd { ind } => {
258 if *mac_role == fidl_common::WlanMacRole::Client {
259 self.set_link_state(fidl_mlme::ControlledPortState::Closed)?;
260 }
261 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::RoamStartInd { ind });
262 }
263 FullmacDriverEvent::RoamResultInd { ind } => {
264 if *mac_role == fidl_common::WlanMacRole::Client {
265 if !self.is_bss_protected
267 && ind.status_code == fidl_ieee80211::StatusCode::Success
268 {
269 self.set_link_state(fidl_mlme::ControlledPortState::Open)?;
270 }
271 }
272 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::RoamResultInd { ind });
273 }
274 FullmacDriverEvent::AuthInd { ind } => {
275 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::AuthenticateInd { ind });
276 }
277 FullmacDriverEvent::DeauthConf { resp } => {
278 if *mac_role == fidl_common::WlanMacRole::Client {
279 self.set_link_state(fidl_mlme::ControlledPortState::Closed)?;
280 }
281 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::DeauthenticateConf { resp });
282 }
283 FullmacDriverEvent::DeauthInd { ind } => {
284 if *mac_role == fidl_common::WlanMacRole::Client {
285 self.set_link_state(fidl_mlme::ControlledPortState::Closed)?;
286 }
287 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::DeauthenticateInd { ind });
288 }
289 FullmacDriverEvent::AssocInd { ind } => {
290 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::AssociateInd { ind });
291 }
292 FullmacDriverEvent::DisassocConf { resp } => {
293 if *mac_role == fidl_common::WlanMacRole::Client {
294 self.set_link_state(fidl_mlme::ControlledPortState::Closed)?;
295 }
296 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::DisassociateConf { resp });
297 }
298 FullmacDriverEvent::DisassocInd { ind } => {
299 if *mac_role == fidl_common::WlanMacRole::Client {
300 self.set_link_state(fidl_mlme::ControlledPortState::Closed)?;
301 }
302 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::DisassociateInd { ind });
303 }
304 FullmacDriverEvent::StartConf { resp } => {
305 if resp.result_code == fidl_mlme::StartResultCode::Success {
306 self.set_link_state(fidl_mlme::ControlledPortState::Open)?;
307 }
308 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::StartConf { resp });
309 }
310 FullmacDriverEvent::StopConf { resp } => {
311 if resp.result_code == fidl_mlme::StopResultCode::Success {
312 self.set_link_state(fidl_mlme::ControlledPortState::Closed)?;
313 }
314 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::StopConf { resp });
315 }
316 FullmacDriverEvent::EapolConf { resp } => {
317 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::EapolConf { resp });
318 }
319 FullmacDriverEvent::OnChannelSwitch { resp } => {
320 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::OnChannelSwitched { info: resp });
321 }
322 FullmacDriverEvent::SignalReport { ind } => {
323 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::SignalReport { ind });
324 }
325 FullmacDriverEvent::EapolInd { ind } => {
326 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::EapolInd { ind });
327 }
328 FullmacDriverEvent::OnPmkAvailable { info } => {
329 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::OnPmkAvailable { info });
330 }
331 FullmacDriverEvent::SaeHandshakeInd { ind } => {
332 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::OnSaeHandshakeInd { ind });
333 }
334 FullmacDriverEvent::SaeFrameRx { frame } => {
335 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::OnSaeFrameRx { frame });
336 }
337 FullmacDriverEvent::OnWmmStatusResp { status, resp } => {
338 self.mlme_event_sink.send(fidl_mlme::MlmeEvent::OnWmmStatusResp { status, resp });
339 }
340 }
341 Ok(DriverState::Running)
342 }
343
344 fn set_link_state(
345 &mut self,
346 new_link_state: fidl_mlme::ControlledPortState,
347 ) -> anyhow::Result<()> {
348 if new_link_state == self.device_link_state {
350 return Ok(());
351 }
352
353 let req = fidl_fullmac::WlanFullmacImplOnLinkStateChangedRequest {
354 online: Some(new_link_state == fidl_mlme::ControlledPortState::Open),
355 ..Default::default()
356 };
357
358 self.device.on_link_state_changed(req)?;
359 self.device_link_state = new_link_state;
360 Ok(())
361 }
362}
363
364#[cfg(test)]
365mod handle_mlme_request_tests {
366 use super::*;
367 use crate::device::test_utils::{DriverCall, FakeFullmacDevice, FakeFullmacDeviceMocks};
368 use assert_matches::assert_matches;
369 use fuchsia_sync::Mutex;
370 use std::sync::Arc;
371 use test_case::test_case;
372 use wlan_common::sink::UnboundedSink;
373 use {
374 fidl_fuchsia_wlan_fullmac as fidl_fullmac, fidl_fuchsia_wlan_internal as fidl_internal,
375 fidl_fuchsia_wlan_stats as fidl_stats,
376 };
377
378 #[test]
379 fn test_scan_request() {
380 let mut h = TestHelper::set_up();
381 let fidl_req = wlan_sme::MlmeRequest::Scan(fidl_mlme::ScanRequest {
382 txn_id: 1,
383 scan_type: fidl_mlme::ScanTypes::Passive,
384 channel_list: vec![2],
385 ssid_list: vec![vec![3u8; 4]],
386 probe_delay: 5,
387 min_channel_time: 6,
388 max_channel_time: 7,
389 });
390
391 h.mlme.handle_mlme_request(fidl_req).unwrap();
392
393 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::StartScan { req })) => req);
394 assert_eq!(driver_req.txn_id, Some(1));
395 assert_eq!(driver_req.scan_type, Some(fidl_fullmac::WlanScanType::Passive));
396 assert_eq!(driver_req.channels, Some(vec![2]));
397 assert_eq!(driver_req.min_channel_time, Some(6));
398 assert_eq!(driver_req.max_channel_time, Some(7));
399 assert_eq!(driver_req.ssids, Some(vec![vec![3u8; 4]]));
400 }
401
402 #[test]
403 fn test_scan_request_empty_ssid_list() {
404 let mut h = TestHelper::set_up();
405 let fidl_req = wlan_sme::MlmeRequest::Scan(fidl_mlme::ScanRequest {
406 txn_id: 1,
407 scan_type: fidl_mlme::ScanTypes::Active,
408 channel_list: vec![2],
409 ssid_list: vec![],
410 probe_delay: 5,
411 min_channel_time: 6,
412 max_channel_time: 7,
413 });
414
415 h.mlme.handle_mlme_request(fidl_req).unwrap();
416
417 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::StartScan { req })) => req);
418 assert_eq!(driver_req.scan_type, Some(fidl_fullmac::WlanScanType::Active));
419 assert!(driver_req.ssids.as_ref().unwrap().is_empty());
420 }
421
422 #[test]
423 fn test_scan_request_empty_channel_list() {
424 let mut h = TestHelper::set_up();
425 let fidl_req = wlan_sme::MlmeRequest::Scan(fidl_mlme::ScanRequest {
426 txn_id: 1,
427 scan_type: fidl_mlme::ScanTypes::Passive,
428 channel_list: vec![],
429 ssid_list: vec![vec![3u8; 4]],
430 probe_delay: 5,
431 min_channel_time: 6,
432 max_channel_time: 7,
433 });
434
435 h.mlme.handle_mlme_request(fidl_req).unwrap();
436
437 assert_matches!(h.driver_calls.try_next(), Err(_));
438 let scan_end = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(fidl_mlme::MlmeEvent::OnScanEnd { end })) => end);
439 assert_eq!(
440 scan_end,
441 fidl_mlme::ScanEnd { txn_id: 1, code: fidl_mlme::ScanResultCode::InvalidArgs }
442 );
443 }
444
445 #[test]
446 fn test_connect_request() {
447 let mut h = TestHelper::set_up_with_link_state(fidl_mlme::ControlledPortState::Open);
448 let fidl_req = wlan_sme::MlmeRequest::Connect(fidl_mlme::ConnectRequest {
449 selected_bss: fidl_common::BssDescription {
450 bssid: [100u8; 6],
451 bss_type: fidl_common::BssType::Infrastructure,
452 beacon_period: 101,
453 capability_info: 102,
454 ies: vec![103u8, 104, 105],
455 channel: fidl_ieee80211::WlanChannel {
456 primary: 106,
457 cbw: fidl_ieee80211::ChannelBandwidth::Cbw40,
458 secondary80: 0,
459 },
460 rssi_dbm: 107,
461 snr_db: 108,
462 },
463 connect_failure_timeout: 1u32,
464 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
465 sae_password: vec![2u8, 3, 4],
466 wep_key: Some(Box::new(fidl_mlme::SetKeyDescriptor {
467 key: vec![5u8, 6],
468 key_id: 7,
469 key_type: fidl_mlme::KeyType::Group,
470 address: [8u8; 6],
471 rsc: 9,
472 cipher_suite_oui: [10u8; 3],
473 cipher_suite_type: fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(
474 11,
475 ),
476 })),
477 security_ie: vec![12u8, 13],
478 owe_public_key: Some(Box::new(fidl_internal::OwePublicKey {
479 group: 14,
480 key: vec![15u8, 16, 17],
481 })),
482 });
483
484 h.mlme.handle_mlme_request(fidl_req).unwrap();
485
486 assert!(h.mlme.is_bss_protected);
487
488 assert_matches!(
489 h.driver_calls.try_next(),
490 Ok(Some(DriverCall::OnLinkStateChanged { req })) => {
491 assert_eq!(req.online, Some(false));
492 }
493 );
494 assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::ConnectReq { req })) => {
495 let selected_bss = req.selected_bss.clone().unwrap();
496 assert_eq!(selected_bss.bssid, [100u8; 6]);
497 assert_eq!(selected_bss.bss_type, fidl_common::BssType::Infrastructure);
498 assert_eq!(selected_bss.beacon_period, 101);
499 assert_eq!(selected_bss.capability_info, 102);
500 assert_eq!(selected_bss.ies, vec![103u8, 104, 105]);
501 assert_eq!(
502 selected_bss.channel,
503 fidl_ieee80211::WlanChannel {
504 primary: 106,
505 cbw: fidl_ieee80211::ChannelBandwidth::Cbw40,
506 secondary80: 0,
507 }
508 );
509 assert_eq!(selected_bss.rssi_dbm, 107);
510 assert_eq!(selected_bss.snr_db, 108);
511
512 assert_eq!(req.connect_failure_timeout, Some(1u32));
513 assert_eq!(req.auth_type, Some(fidl_fullmac::WlanAuthType::OpenSystem));
514 assert_eq!(req.sae_password, Some(vec![2u8, 3, 4]));
515
516 let wep_key_desc = req.wep_key_desc.clone().unwrap();
517 assert_eq!(wep_key_desc.key, Some(vec![5u8, 6]));
518 assert_eq!(wep_key_desc.key_id, Some(7));
519 assert_eq!(wep_key_desc.key_type, Some(fidl_ieee80211::KeyType::Group));
520 assert_eq!(wep_key_desc.peer_addr, Some([8u8; 6]));
521 assert_eq!(wep_key_desc.rsc, Some(9));
522 assert_eq!(wep_key_desc.cipher_oui, Some([10u8; 3]));
523 assert_eq!(wep_key_desc.cipher_type, fidl_ieee80211::CipherSuiteType::from_primitive(11));
524
525 assert_eq!(req.security_ie, Some(vec![12u8, 13]));
526 assert_eq!(req.owe_public_key, Some(fidl_fullmac::WlanFullmacOwePublicKey {
527 group: Some(14),
528 key: Some(vec![15u8, 16, 17]),
529 ..Default::default()
530 }));
531 });
532 }
533
534 #[test]
535 fn test_reconnect_request() {
536 let mut h = TestHelper::set_up();
537 let fidl_req = wlan_sme::MlmeRequest::Reconnect(fidl_mlme::ReconnectRequest {
538 peer_sta_address: [1u8; 6],
539 });
540
541 h.mlme.handle_mlme_request(fidl_req).unwrap();
542
543 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::ReconnectReq { req })) => req);
544 assert_eq!(
545 driver_req,
546 fidl_fullmac::WlanFullmacImplReconnectRequest {
547 peer_sta_address: Some([1u8; 6]),
548 ..Default::default()
549 }
550 );
551 }
552
553 #[test]
554 fn test_authenticate_response() {
555 let mut h = TestHelper::set_up();
556 let fidl_req = wlan_sme::MlmeRequest::AuthResponse(fidl_mlme::AuthenticateResponse {
557 peer_sta_address: [1u8; 6],
558 result_code: fidl_mlme::AuthenticateResultCode::Success,
559 });
560
561 h.mlme.handle_mlme_request(fidl_req).unwrap();
562
563 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::AuthResp { resp })) => resp);
564 assert_eq!(
565 driver_req,
566 fidl_fullmac::WlanFullmacImplAuthRespRequest {
567 peer_sta_address: Some([1u8; 6]),
568 result_code: Some(fidl_fullmac::WlanAuthResult::Success),
569 ..Default::default()
570 }
571 );
572 }
573
574 #[test]
575 fn test_deauthenticate_request() {
576 let mut h = TestHelper::set_up_with_link_state(fidl_mlme::ControlledPortState::Open);
577 let fidl_req = wlan_sme::MlmeRequest::Deauthenticate(fidl_mlme::DeauthenticateRequest {
578 peer_sta_address: [1u8; 6],
579 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
580 });
581
582 h.mlme.handle_mlme_request(fidl_req).unwrap();
583
584 assert_matches!(
585 h.driver_calls.try_next(),
586 Ok(Some(DriverCall::OnLinkStateChanged { req })) => {
587 assert_eq!(req.online, Some(false));
588 }
589 );
590 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::DeauthReq { req })) => req);
591 assert_eq!(driver_req.peer_sta_address, Some([1u8; 6]));
592 assert_eq!(driver_req.reason_code, Some(fidl_ieee80211::ReasonCode::LeavingNetworkDeauth));
593 }
594
595 #[test]
596 fn test_associate_response() {
597 let mut h = TestHelper::set_up();
598 let fidl_req = wlan_sme::MlmeRequest::AssocResponse(fidl_mlme::AssociateResponse {
599 peer_sta_address: [1u8; 6],
600 result_code: fidl_mlme::AssociateResultCode::Success,
601 association_id: 2,
602 capability_info: 3,
603 rates: vec![4, 5],
604 });
605
606 h.mlme.handle_mlme_request(fidl_req).unwrap();
607
608 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::AssocResp { resp })) => resp);
609 assert_eq!(driver_req.peer_sta_address, Some([1u8; 6]));
610 assert_eq!(driver_req.result_code, Some(fidl_fullmac::WlanAssocResult::Success));
611 assert_eq!(driver_req.association_id, Some(2));
612 }
613
614 #[test]
615 fn test_disassociate_request() {
616 let mut h = TestHelper::set_up_with_link_state(fidl_mlme::ControlledPortState::Open);
617 let fidl_req = wlan_sme::MlmeRequest::Disassociate(fidl_mlme::DisassociateRequest {
618 peer_sta_address: [1u8; 6],
619 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDisassoc,
620 });
621
622 h.mlme.handle_mlme_request(fidl_req).unwrap();
623
624 assert_matches!(
625 h.driver_calls.try_next(),
626 Ok(Some(DriverCall::OnLinkStateChanged { req })) => {
627 assert_eq!(req.online, Some(false));
628 }
629 );
630
631 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::Disassoc{ req })) => req);
632 assert_eq!(driver_req.peer_sta_address, Some([1u8; 6]));
633 assert_eq!(
634 driver_req.reason_code,
635 Some(fidl_ieee80211::ReasonCode::LeavingNetworkDisassoc)
636 );
637 }
638
639 #[test]
640 fn test_start_request() {
641 let mut h = TestHelper::set_up();
642 const SSID_LEN: usize = 2;
643 const RSNE_LEN: usize = 15;
644 let fidl_req = wlan_sme::MlmeRequest::Start(fidl_mlme::StartRequest {
645 ssid: vec![1u8; SSID_LEN],
646 bss_type: fidl_common::BssType::Infrastructure,
647 beacon_period: 3,
648 dtim_period: 4,
649 channel: 5,
650 capability_info: 6,
651 rates: vec![7, 8, 9],
652 country: fidl_mlme::Country { alpha2: [10, 11], suffix: 12 },
653 mesh_id: vec![13],
654 rsne: Some(vec![14; RSNE_LEN]),
655 phy: fidl_common::WlanPhyType::Vht,
656 channel_bandwidth: fidl_ieee80211::ChannelBandwidth::Cbw80,
657 });
658
659 h.mlme.handle_mlme_request(fidl_req).unwrap();
660
661 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::StartBss { req })) => req);
662
663 assert_eq!(driver_req.ssid, Some(vec![1u8; SSID_LEN]));
664 assert_eq!(driver_req.bss_type, Some(fidl_common::BssType::Infrastructure));
665 assert_eq!(driver_req.beacon_period, Some(3));
666 assert_eq!(driver_req.dtim_period, Some(4));
667 assert_eq!(driver_req.channel, Some(5));
668 assert_ne!(driver_req.rsne, Some(vec![14 as u8, RSNE_LEN as u8]));
669 assert_eq!(driver_req.vendor_ie, Some(vec![]));
670 }
671
672 #[test]
673 fn test_stop_request() {
674 let mut h = TestHelper::set_up();
675 const SSID_LEN: usize = 2;
676 let fidl_req =
677 wlan_sme::MlmeRequest::Stop(fidl_mlme::StopRequest { ssid: vec![1u8; SSID_LEN] });
678
679 h.mlme.handle_mlme_request(fidl_req).unwrap();
680
681 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::StopBss { req })) => req);
682 assert_eq!(driver_req.ssid, Some(vec![1u8; SSID_LEN]));
683 }
684
685 #[test]
686 fn test_set_keys_request() {
687 let mut h = TestHelper::set_up();
688 let fidl_req = wlan_sme::MlmeRequest::SetKeys(fidl_mlme::SetKeysRequest {
689 keylist: vec![fidl_mlme::SetKeyDescriptor {
690 key: vec![5u8, 6],
691 key_id: 7,
692 key_type: fidl_mlme::KeyType::Group,
693 address: [8u8; 6],
694 rsc: 9,
695 cipher_suite_oui: [10u8; 3],
696 cipher_suite_type: fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(
697 11,
698 ),
699 }],
700 });
701
702 h.mlme.handle_mlme_request(fidl_req).unwrap();
703
704 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::SetKeys { req })) => req);
705 assert_eq!(driver_req.key_descriptors.as_ref().unwrap().len(), 1 as usize);
706 let key_descriptors = driver_req.key_descriptors.as_ref().unwrap();
707 assert_eq!(key_descriptors[0].key_id, Some(7));
708 assert_eq!(key_descriptors[0].key_type, Some(fidl_ieee80211::KeyType::Group));
709 assert_eq!(key_descriptors[0].peer_addr, Some([8u8; 6]));
710 assert_eq!(key_descriptors[0].rsc, Some(9));
711 assert_eq!(key_descriptors[0].cipher_oui, Some([10u8; 3]));
712 assert_eq!(
713 key_descriptors[0].cipher_type,
714 Some(fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(11))
715 );
716
717 let conf = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(fidl_mlme::MlmeEvent::SetKeysConf { conf })) => conf);
718 assert_eq!(
719 conf,
720 fidl_mlme::SetKeysConfirm {
721 results: vec![fidl_mlme::SetKeyResult { key_id: 7, status: 0 }]
722 }
723 );
724 }
725
726 #[test]
727 fn test_set_keys_request_partial_failure() {
728 let mut h = TestHelper::set_up();
729 const NUM_KEYS: usize = 3;
730 h.fake_device.lock().set_keys_resp_mock =
731 Some(fidl_fullmac::WlanFullmacSetKeysResp { statuslist: [0i32, 1, 0].to_vec() });
732 let mut keylist = vec![];
733 let key = fidl_mlme::SetKeyDescriptor {
734 key: vec![5u8, 6],
735 key_id: 7,
736 key_type: fidl_mlme::KeyType::Group,
737 address: [8u8; 6],
738 rsc: 9,
739 cipher_suite_oui: [10u8; 3],
740 cipher_suite_type: fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(11),
741 };
742 for i in 0..NUM_KEYS {
743 keylist.push(fidl_mlme::SetKeyDescriptor { key_id: i as u16, ..key.clone() });
744 }
745 let fidl_req = wlan_sme::MlmeRequest::SetKeys(fidl_mlme::SetKeysRequest { keylist });
746
747 h.mlme.handle_mlme_request(fidl_req).unwrap();
748
749 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::SetKeys { req })) => req);
750 assert_eq!(driver_req.key_descriptors.as_ref().unwrap().len(), NUM_KEYS as usize);
751 let key_descriptors = driver_req.key_descriptors.unwrap();
752 for i in 0..NUM_KEYS {
753 assert_eq!(key_descriptors[i].key_id, Some(i as u16));
754 }
755
756 let conf = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(fidl_mlme::MlmeEvent::SetKeysConf { conf })) => conf);
757 assert_eq!(
758 conf,
759 fidl_mlme::SetKeysConfirm {
760 results: vec![
761 fidl_mlme::SetKeyResult { key_id: 0, status: 0 },
762 fidl_mlme::SetKeyResult { key_id: 1, status: 1 },
763 fidl_mlme::SetKeyResult { key_id: 2, status: 0 },
764 ]
765 }
766 );
767 }
768
769 #[test]
770 fn test_set_keys_request_too_many_keys() {
771 let mut h = TestHelper::set_up();
772 let key = fidl_mlme::SetKeyDescriptor {
773 key: vec![5u8, 6],
774 key_id: 7,
775 key_type: fidl_mlme::KeyType::Group,
776 address: [8u8; 6],
777 rsc: 9,
778 cipher_suite_oui: [10u8; 3],
779 cipher_suite_type: fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(11),
780 };
781 let fidl_req = wlan_sme::MlmeRequest::SetKeys(fidl_mlme::SetKeysRequest {
782 keylist: vec![key.clone(); 5],
783 });
784
785 assert!(h.mlme.handle_mlme_request(fidl_req).is_err());
786
787 assert_matches!(h.driver_calls.try_next(), Err(_));
789 assert_matches!(h.mlme_event_receiver.try_next(), Err(_));
790 }
791
792 #[test]
793 fn test_set_keys_request_when_resp_has_different_num_keys() {
794 let mut h = TestHelper::set_up();
795 h.fake_device.lock().set_keys_resp_mock =
796 Some(fidl_fullmac::WlanFullmacSetKeysResp { statuslist: [0i32; 2].to_vec() });
797 let fidl_req = wlan_sme::MlmeRequest::SetKeys(fidl_mlme::SetKeysRequest {
798 keylist: vec![fidl_mlme::SetKeyDescriptor {
799 key: vec![5u8, 6],
800 key_id: 7,
801 key_type: fidl_mlme::KeyType::Group,
802 address: [8u8; 6],
803 rsc: 9,
804 cipher_suite_oui: [10u8; 3],
805 cipher_suite_type: fidl_ieee80211::CipherSuiteType::from_primitive_allow_unknown(
806 11,
807 ),
808 }],
809 });
810
811 assert!(h.mlme.handle_mlme_request(fidl_req).is_err());
813
814 assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::SetKeys { .. })));
815 assert_matches!(h.mlme_event_receiver.try_next(), Err(_));
818 }
819
820 #[test]
821 fn test_eapol_request() {
822 let mut h = TestHelper::set_up();
823 let fidl_req = wlan_sme::MlmeRequest::Eapol(fidl_mlme::EapolRequest {
824 src_addr: [1u8; 6],
825 dst_addr: [2u8; 6],
826 data: vec![3u8; 4],
827 });
828
829 h.mlme.handle_mlme_request(fidl_req).unwrap();
830
831 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::EapolTx { req })) => req);
832 assert_eq!(driver_req.src_addr, Some([1u8; 6]));
833 assert_eq!(driver_req.dst_addr, Some([2u8; 6]));
834 assert_eq!(driver_req.data, Some(vec![3u8; 4]));
835 }
836
837 #[test_case(fidl_mlme::ControlledPortState::Open, true; "online")]
838 #[test_case(fidl_mlme::ControlledPortState::Closed, false; "offline")]
839 #[fuchsia::test(add_test_attr = false)]
840 fn test_set_ctrl_port(
841 controlled_port_state: fidl_mlme::ControlledPortState,
842 expected_link_state: bool,
843 ) {
844 let mut h = match controlled_port_state {
845 fidl_mlme::ControlledPortState::Open => TestHelper::set_up(),
846 fidl_mlme::ControlledPortState::Closed => {
847 TestHelper::set_up_with_link_state(fidl_mlme::ControlledPortState::Open)
848 }
849 };
850 let fidl_req = wlan_sme::MlmeRequest::SetCtrlPort(fidl_mlme::SetControlledPortRequest {
851 peer_sta_address: [1u8; 6],
852 state: controlled_port_state,
853 });
854
855 h.mlme.handle_mlme_request(fidl_req).unwrap();
856
857 assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::OnLinkStateChanged { req })) => {
858 assert_eq!(req.online, Some(expected_link_state));
859 });
860 }
861
862 #[test]
863 fn test_query_telemetry_support() {
864 let mut h = TestHelper::set_up();
865 let mocked_support = Ok(fidl_stats::TelemetrySupport {
866 inspect_counter_configs: Some(vec![fidl_stats::InspectCounterConfig {
867 counter_id: Some(1),
868 counter_name: Some("foo_counter".to_string()),
869 ..Default::default()
870 }]),
871 ..Default::default()
872 });
873 h.fake_device.lock().query_telemetry_support_mock.replace(mocked_support.clone());
874 let (support_responder, mut support_receiver) = wlan_sme::responder::Responder::new();
875 let fidl_req = wlan_sme::MlmeRequest::QueryTelemetrySupport(support_responder);
876
877 h.mlme.handle_mlme_request(fidl_req).unwrap();
878
879 assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::QueryTelemetrySupport)));
880 let support = assert_matches!(support_receiver.try_recv(), Ok(Some(support)) => support);
881 assert_eq!(support, mocked_support);
882 }
883
884 #[test]
885 fn test_get_iface_stats() {
886 let mut h = TestHelper::set_up();
887 let mocked_stats = fidl_stats::IfaceStats {
888 connection_stats: Some(fidl_stats::ConnectionStats {
889 connection_id: Some(1),
890 rx_unicast_drop: Some(11),
891 rx_unicast_total: Some(22),
892 rx_multicast: Some(33),
893 tx_total: Some(44),
894 tx_drop: Some(55),
895 ..Default::default()
896 }),
897 ..Default::default()
898 };
899 h.fake_device
900 .lock()
901 .get_iface_stats_mock
902 .replace(fidl_mlme::GetIfaceStatsResponse::Stats(mocked_stats));
903 let (stats_responder, mut stats_receiver) = wlan_sme::responder::Responder::new();
904 let fidl_req = wlan_sme::MlmeRequest::GetIfaceStats(stats_responder);
905
906 h.mlme.handle_mlme_request(fidl_req).unwrap();
907
908 assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::GetIfaceStats)));
909 let stats = assert_matches!(stats_receiver.try_recv(), Ok(Some(stats)) => stats);
910 let stats = assert_matches!(stats, fidl_mlme::GetIfaceStatsResponse::Stats(stats) => stats);
911 assert_eq!(
912 stats,
913 fidl_stats::IfaceStats {
914 connection_stats: Some(fidl_stats::ConnectionStats {
915 connection_id: Some(1),
916 rx_unicast_drop: Some(11),
917 rx_unicast_total: Some(22),
918 rx_multicast: Some(33),
919 tx_total: Some(44),
920 tx_drop: Some(55),
921 ..Default::default()
922 }),
923 ..Default::default()
924 }
925 );
926 }
927
928 #[test]
929 fn test_get_iface_histogram_stats() {
930 let mut h = TestHelper::set_up();
931
932 let mocked_stats = fidl_stats::IfaceHistogramStats {
933 noise_floor_histograms: Some(vec![fidl_stats::NoiseFloorHistogram {
934 hist_scope: fidl_stats::HistScope::Station,
935 antenna_id: None,
936 noise_floor_samples: vec![fidl_stats::HistBucket {
937 bucket_index: 2,
938 num_samples: 3,
939 }],
940 invalid_samples: 4,
941 }]),
942 rssi_histograms: Some(vec![fidl_stats::RssiHistogram {
943 hist_scope: fidl_stats::HistScope::PerAntenna,
944 antenna_id: Some(Box::new(fidl_stats::AntennaId {
945 freq: fidl_stats::AntennaFreq::Antenna5G,
946 index: 5,
947 })),
948 rssi_samples: vec![fidl_stats::HistBucket { bucket_index: 6, num_samples: 7 }],
949 invalid_samples: 8,
950 }]),
951 rx_rate_index_histograms: Some(vec![fidl_stats::RxRateIndexHistogram {
952 hist_scope: fidl_stats::HistScope::Station,
953 antenna_id: None,
954 rx_rate_index_samples: vec![fidl_stats::HistBucket {
955 bucket_index: 10,
956 num_samples: 11,
957 }],
958 invalid_samples: 12,
959 }]),
960 snr_histograms: Some(vec![fidl_stats::SnrHistogram {
961 hist_scope: fidl_stats::HistScope::PerAntenna,
962 antenna_id: Some(Box::new(fidl_stats::AntennaId {
963 freq: fidl_stats::AntennaFreq::Antenna2G,
964 index: 13,
965 })),
966 snr_samples: vec![fidl_stats::HistBucket { bucket_index: 14, num_samples: 15 }],
967 invalid_samples: 16,
968 }]),
969 ..Default::default()
970 };
971
972 h.fake_device
973 .lock()
974 .get_iface_histogram_stats_mock
975 .replace(fidl_mlme::GetIfaceHistogramStatsResponse::Stats(mocked_stats.clone()));
976 let (stats_responder, mut stats_receiver) = wlan_sme::responder::Responder::new();
977 let fidl_req = wlan_sme::MlmeRequest::GetIfaceHistogramStats(stats_responder);
978
979 h.mlme.handle_mlme_request(fidl_req).unwrap();
980
981 assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::GetIfaceHistogramStats)));
982 let stats = assert_matches!(stats_receiver.try_recv(), Ok(Some(stats)) => stats);
983 let stats = assert_matches!(stats, fidl_mlme::GetIfaceHistogramStatsResponse::Stats(stats) => stats);
984 assert_eq!(stats, mocked_stats);
985 }
986
987 #[test]
988 fn test_sae_handshake_resp() {
989 let mut h = TestHelper::set_up();
990 let fidl_req = wlan_sme::MlmeRequest::SaeHandshakeResp(fidl_mlme::SaeHandshakeResponse {
991 peer_sta_address: [1u8; 6],
992 status_code: fidl_ieee80211::StatusCode::AntiCloggingTokenRequired,
993 });
994
995 h.mlme.handle_mlme_request(fidl_req).unwrap();
996
997 let driver_req = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::SaeHandshakeResp { resp })) => resp);
998 assert_eq!(driver_req.peer_sta_address.unwrap(), [1u8; 6]);
999 assert_eq!(
1000 driver_req.status_code.unwrap(),
1001 fidl_ieee80211::StatusCode::AntiCloggingTokenRequired
1002 );
1003 }
1004
1005 #[test]
1006 fn test_convert_sae_frame() {
1007 let mut h = TestHelper::set_up();
1008 let fidl_req = wlan_sme::MlmeRequest::SaeFrameTx(fidl_mlme::SaeFrame {
1009 peer_sta_address: [1u8; 6],
1010 status_code: fidl_ieee80211::StatusCode::Success,
1011 seq_num: 2,
1012 sae_fields: vec![3u8; 4],
1013 });
1014
1015 h.mlme.handle_mlme_request(fidl_req).unwrap();
1016
1017 let driver_frame = assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::SaeFrameTx { frame })) => frame);
1018 assert_eq!(driver_frame.peer_sta_address.unwrap(), [1u8; 6]);
1019 assert_eq!(driver_frame.status_code.unwrap(), fidl_ieee80211::StatusCode::Success);
1020 assert_eq!(driver_frame.seq_num.unwrap(), 2);
1021 assert_eq!(driver_frame.sae_fields.unwrap(), vec![3u8; 4]);
1022 }
1023
1024 #[test]
1025 fn test_wmm_status_req() {
1026 let mut h = TestHelper::set_up();
1027 let fidl_req = wlan_sme::MlmeRequest::WmmStatusReq;
1028
1029 h.mlme.handle_mlme_request(fidl_req).unwrap();
1030
1031 assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::WmmStatusReq)));
1032 }
1033
1034 #[test]
1035 fn test_set_mac_address_req() {
1036 let mut h = TestHelper::set_up();
1037 let (responder, mut receiver) = wlan_sme::responder::Responder::new();
1038 let mac_addr = [1u8; 6];
1039 let fidl_req = wlan_sme::MlmeRequest::SetMacAddress(mac_addr, responder);
1040
1041 h.mlme.handle_mlme_request(fidl_req).unwrap();
1042 assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::SetMacAddress { req })) => {
1043 assert_eq!(req.mac_addr, mac_addr);
1044 });
1045 assert_matches!(receiver.try_recv(), Ok(Some(Ok(()))));
1046 }
1047
1048 pub struct TestHelper {
1049 fake_device: Arc<Mutex<FakeFullmacDeviceMocks>>,
1050 mlme: MlmeMainLoop<FakeFullmacDevice>,
1051 mlme_event_receiver: mpsc::UnboundedReceiver<fidl_mlme::MlmeEvent>,
1052 driver_calls: mpsc::UnboundedReceiver<DriverCall>,
1053 _mlme_request_sender: mpsc::UnboundedSender<wlan_sme::MlmeRequest>,
1054 _driver_event_sender: mpsc::UnboundedSender<FullmacDriverEvent>,
1055 }
1056
1057 impl TestHelper {
1058 pub fn set_up_with_link_state(device_link_state: fidl_mlme::ControlledPortState) -> Self {
1059 let (fake_device, driver_calls) = FakeFullmacDevice::new();
1060 let (mlme_request_sender, mlme_request_stream) = mpsc::unbounded();
1061 let (mlme_event_sender, mlme_event_receiver) = mpsc::unbounded();
1062 let mlme_event_sink = UnboundedSink::new(mlme_event_sender);
1063
1064 let (driver_event_sender, driver_event_stream) = mpsc::unbounded();
1065 let mocks = fake_device.mocks.clone();
1066
1067 let mlme = MlmeMainLoop {
1068 device: fake_device,
1069 mlme_request_stream,
1070 mlme_event_sink,
1071 driver_event_stream,
1072 is_bss_protected: false,
1073 device_link_state,
1074 };
1075 Self {
1076 fake_device: mocks,
1077 mlme,
1078 mlme_event_receiver,
1079 driver_calls,
1080 _mlme_request_sender: mlme_request_sender,
1081 _driver_event_sender: driver_event_sender,
1082 }
1083 }
1084
1085 pub fn set_up() -> Self {
1087 Self::set_up_with_link_state(fidl_mlme::ControlledPortState::Closed)
1088 }
1089 }
1090}
1091#[cfg(test)]
1092mod handle_driver_event_tests {
1093 use super::*;
1094 use crate::device::test_utils::{DriverCall, FakeFullmacDevice, FakeFullmacDeviceMocks};
1095 use assert_matches::assert_matches;
1096 use fuchsia_sync::Mutex;
1097 use futures::Future;
1098 use futures::channel::mpsc;
1099 use futures::task::Poll;
1100 use std::pin::Pin;
1101 use std::sync::Arc;
1102 use test_case::test_case;
1103 use wlan_common::fake_fidl_bss_description;
1104 use wlan_common::sink::UnboundedSink;
1105 use {
1106 fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211, fidl_fuchsia_wlan_internal as fidl_internal,
1107 fidl_fuchsia_wlan_mlme as fidl_mlme, fuchsia_async as fasync,
1108 };
1109
1110 fn create_bss_descriptions() -> fidl_common::BssDescription {
1111 fidl_common::BssDescription {
1112 bssid: [9u8; 6],
1113 bss_type: fidl_common::BssType::Infrastructure,
1114 beacon_period: 1,
1115 capability_info: 2,
1116 ies: vec![3, 4, 5],
1117 channel: fidl_ieee80211::WlanChannel {
1118 primary: 6,
1119 cbw: fidl_ieee80211::ChannelBandwidth::Cbw20,
1120 secondary80: 0,
1121 },
1122 rssi_dbm: 7,
1123 snr_db: 8,
1124 }
1125 }
1126
1127 fn create_connect_request(security_ie: Vec<u8>) -> wlan_sme::MlmeRequest {
1128 wlan_sme::MlmeRequest::Connect(fidl_mlme::ConnectRequest {
1129 selected_bss: fake_fidl_bss_description!(Wpa2),
1130 connect_failure_timeout: 1u32,
1131 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1132 sae_password: vec![2u8, 3, 4],
1133 wep_key: None,
1134 security_ie,
1135 owe_public_key: None,
1136 })
1137 }
1138
1139 #[test]
1140 fn test_on_scan_result() {
1141 let (mut h, mut test_fut) = TestHelper::set_up();
1142 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1143
1144 let bss = create_bss_descriptions();
1145 let scan_result = fidl_fullmac::WlanFullmacImplIfcOnScanResultRequest {
1146 txn_id: Some(42u64),
1147 timestamp_nanos: Some(1337i64),
1148 bss: Some(bss.clone()),
1149 ..Default::default()
1150 };
1151 assert_matches!(
1152 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.on_scan_result(&scan_result)),
1153 Poll::Ready(Ok(()))
1154 );
1155 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1156
1157 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1158 let result =
1159 assert_matches!(event, fidl_mlme::MlmeEvent::OnScanResult { result } => result);
1160 assert_eq!(result, fidl_mlme::ScanResult { txn_id: 42u64, timestamp_nanos: 1337i64, bss });
1161 }
1162
1163 #[test]
1164 fn test_on_scan_end() {
1165 let (mut h, mut test_fut) = TestHelper::set_up();
1166 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1167
1168 let scan_end = fidl_fullmac::WlanFullmacImplIfcOnScanEndRequest {
1169 txn_id: Some(42u64),
1170 code: Some(fidl_fullmac::WlanScanResult::Success),
1171 ..Default::default()
1172 };
1173 assert_matches!(
1174 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.on_scan_end(&scan_end)),
1175 Poll::Ready(Ok(()))
1176 );
1177 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1178
1179 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1180 let end = assert_matches!(event, fidl_mlme::MlmeEvent::OnScanEnd { end } => end);
1181 assert_eq!(
1182 end,
1183 fidl_mlme::ScanEnd { txn_id: 42u64, code: fidl_mlme::ScanResultCode::Success }
1184 );
1185 }
1186
1187 #[test]
1188 fn test_connect_conf() {
1189 let (mut h, mut test_fut) = TestHelper::set_up();
1190 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1191
1192 let connect_conf = fidl_fullmac::WlanFullmacImplIfcConnectConfRequest {
1193 peer_sta_address: Some([1u8; 6]),
1194 result_code: Some(fidl_ieee80211::StatusCode::Success),
1195 association_id: Some(2),
1196 association_ies: Some(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]),
1197 ..Default::default()
1198 };
1199 assert_matches!(
1200 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.connect_conf(&connect_conf)),
1201 Poll::Ready(Ok(()))
1202 );
1203 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1204
1205 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1206 let conf = assert_matches!(event, fidl_mlme::MlmeEvent::ConnectConf { resp } => resp);
1207 assert_eq!(
1208 conf,
1209 fidl_mlme::ConnectConfirm {
1210 peer_sta_address: [1u8; 6],
1211 result_code: fidl_ieee80211::StatusCode::Success,
1212 association_id: 2,
1213 association_ies: vec![1, 2, 3, 4, 5, 6, 7, 8, 9],
1214 }
1215 );
1216 }
1217
1218 #[test_case(true, fidl_ieee80211::StatusCode::Success, false; "secure connect with success status is not online yet")]
1219 #[test_case(false, fidl_ieee80211::StatusCode::Success, true; "insecure connect with success status is online right away")]
1220 #[test_case(true, fidl_ieee80211::StatusCode::RefusedReasonUnspecified, false; "secure connect with failed status is not online")]
1221 #[test_case(false, fidl_ieee80211::StatusCode::RefusedReasonUnspecified, false; "insecure connect with failed status in not online")]
1222 #[fuchsia::test(add_test_attr = false)]
1223 fn test_connect_req_connect_conf_link_state(
1224 secure_connect: bool,
1225 connect_result_code: fidl_ieee80211::StatusCode,
1226 expected_online: bool,
1227 ) {
1228 let (mut h, mut test_fut) =
1229 TestHelper::set_up_with_link_state(fidl_mlme::ControlledPortState::Open);
1230 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1231
1232 let connect_req =
1233 create_connect_request(if secure_connect { vec![7u8, 8] } else { vec![] });
1234 h.mlme_request_sender
1235 .unbounded_send(connect_req)
1236 .expect("sending ConnectReq should succeed");
1237 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1238
1239 let connect_conf = fidl_fullmac::WlanFullmacImplIfcConnectConfRequest {
1240 peer_sta_address: Some([1u8; 6]),
1241 result_code: Some(connect_result_code),
1242 association_id: Some(2),
1243 association_ies: Some(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]),
1244 ..Default::default()
1245 };
1246
1247 assert_matches!(
1248 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.connect_conf(&connect_conf)),
1249 Poll::Ready(Ok(()))
1250 );
1251 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1252
1253 assert_matches!(
1254 h.driver_calls.try_next(),
1255 Ok(Some(DriverCall::OnLinkStateChanged { req })) => {
1256 assert_eq!(req.online, Some(false));
1257 }
1258 );
1259 assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::ConnectReq { .. })));
1260 if expected_online {
1261 assert_matches!(
1262 h.driver_calls.try_next(),
1263 Ok(Some(DriverCall::OnLinkStateChanged { req })) => {
1264 assert_eq!(req.online, Some(true));
1265 }
1266 );
1267 } else {
1268 assert_matches!(h.driver_calls.try_next(), Err(_));
1269 }
1270 }
1271
1272 #[test]
1273 fn test_auth_ind() {
1274 let (mut h, mut test_fut) = TestHelper::set_up();
1275 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1276
1277 let auth_ind = fidl_fullmac::WlanFullmacImplIfcAuthIndRequest {
1278 peer_sta_address: Some([1u8; 6]),
1279 auth_type: Some(fidl_fullmac::WlanAuthType::OpenSystem),
1280 ..Default::default()
1281 };
1282 assert_matches!(
1283 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.auth_ind(&auth_ind)),
1284 Poll::Ready(Ok(()))
1285 );
1286 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1287
1288 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1289 let ind = assert_matches!(event, fidl_mlme::MlmeEvent::AuthenticateInd { ind } => ind);
1290 assert_eq!(
1291 ind,
1292 fidl_mlme::AuthenticateIndication {
1293 peer_sta_address: [1u8; 6],
1294 auth_type: fidl_mlme::AuthenticationTypes::OpenSystem,
1295 }
1296 );
1297 }
1298
1299 #[test_case(fidl_common::WlanMacRole::Client; "client")]
1300 #[test_case(fidl_common::WlanMacRole::Ap; "ap")]
1301 #[fuchsia::test(add_test_attr = false)]
1302 fn test_deauth_conf(mac_role: fidl_common::WlanMacRole) {
1303 let (mut h, mut test_fut) =
1304 TestHelper::set_up_with_link_state(fidl_mlme::ControlledPortState::Open);
1305 h.fake_device.lock().query_device_info_mock.as_mut().unwrap().role = Some(mac_role);
1306 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1307
1308 let deauth_conf = fidl_fullmac::WlanFullmacImplIfcDeauthConfRequest {
1309 peer_sta_address: Some([1u8; 6]),
1310 ..Default::default()
1311 };
1312 assert_matches!(
1313 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.deauth_conf(&deauth_conf)),
1314 Poll::Ready(Ok(()))
1315 );
1316 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1317
1318 if mac_role == fidl_common::WlanMacRole::Client {
1319 assert_matches!(
1320 h.driver_calls.try_next(),
1321 Ok(Some(DriverCall::OnLinkStateChanged { req })) => {
1322 assert_eq!(req.online, Some(false));
1323 }
1324 );
1325 } else {
1326 assert_matches!(h.driver_calls.try_next(), Err(_));
1327 }
1328
1329 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1330 let conf =
1331 assert_matches!(event, fidl_mlme::MlmeEvent::DeauthenticateConf { resp } => resp);
1332 assert_eq!(conf, fidl_mlme::DeauthenticateConfirm { peer_sta_address: [1u8; 6] });
1333 }
1334
1335 #[test_case(fidl_common::WlanMacRole::Client; "client")]
1336 #[test_case(fidl_common::WlanMacRole::Ap; "ap")]
1337 #[fuchsia::test(add_test_attr = false)]
1338 fn test_deauth_ind(mac_role: fidl_common::WlanMacRole) {
1339 let (mut h, mut test_fut) =
1340 TestHelper::set_up_with_link_state(fidl_mlme::ControlledPortState::Open);
1341 h.fake_device.lock().query_device_info_mock.as_mut().unwrap().role = Some(mac_role);
1342 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1343
1344 let deauth_ind = fidl_fullmac::WlanFullmacImplIfcDeauthIndRequest {
1345 peer_sta_address: Some([1u8; 6]),
1346 reason_code: Some(fidl_ieee80211::ReasonCode::LeavingNetworkDeauth),
1347 locally_initiated: Some(true),
1348 ..Default::default()
1349 };
1350 assert_matches!(
1351 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.deauth_ind(&deauth_ind)),
1352 Poll::Ready(Ok(()))
1353 );
1354 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1355
1356 if mac_role == fidl_common::WlanMacRole::Client {
1357 assert_matches!(
1358 h.driver_calls.try_next(),
1359 Ok(Some(DriverCall::OnLinkStateChanged { req })) =>{
1360 assert_eq!(req.online, Some(false));
1361 }
1362 );
1363 } else {
1364 assert_matches!(h.driver_calls.try_next(), Err(_));
1365 }
1366
1367 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1368 let ind = assert_matches!(event, fidl_mlme::MlmeEvent::DeauthenticateInd { ind } => ind);
1369 assert_eq!(
1370 ind,
1371 fidl_mlme::DeauthenticateIndication {
1372 peer_sta_address: [1u8; 6],
1373 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
1374 locally_initiated: true,
1375 }
1376 );
1377 }
1378
1379 #[test]
1380 fn test_assoc_ind() {
1381 let (mut h, mut test_fut) = TestHelper::set_up();
1382 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1383
1384 let assoc_ind = fidl_fullmac::WlanFullmacImplIfcAssocIndRequest {
1385 peer_sta_address: Some([1u8; 6]),
1386 listen_interval: Some(2),
1387 ssid: vec![3u8; 4].into(),
1388 rsne: Some(vec![5u8; 6]),
1389 vendor_ie: Some(vec![7u8; 8]),
1390 ..Default::default()
1391 };
1392 assert_matches!(
1393 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.assoc_ind(&assoc_ind)),
1394 Poll::Ready(Ok(()))
1395 );
1396 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1397
1398 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1399 let ind = assert_matches!(event, fidl_mlme::MlmeEvent::AssociateInd { ind } => ind);
1400 assert_eq!(
1401 ind,
1402 fidl_mlme::AssociateIndication {
1403 peer_sta_address: [1u8; 6],
1404 capability_info: 0,
1405 listen_interval: 2,
1406 ssid: Some(vec![3u8; 4]),
1407 rates: vec![],
1408 rsne: Some(vec![5u8; 6]),
1409 }
1410 );
1411 }
1412
1413 #[test_case(fidl_common::WlanMacRole::Client; "client")]
1414 #[test_case(fidl_common::WlanMacRole::Ap; "ap")]
1415 #[fuchsia::test(add_test_attr = false)]
1416 fn test_disassoc_conf(mac_role: fidl_common::WlanMacRole) {
1417 let (mut h, mut test_fut) =
1418 TestHelper::set_up_with_link_state(fidl_mlme::ControlledPortState::Open);
1419 h.fake_device.lock().query_device_info_mock.as_mut().unwrap().role = Some(mac_role);
1420 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1421
1422 let disassoc_conf = fidl_fullmac::WlanFullmacImplIfcDisassocConfRequest {
1423 status: Some(1),
1424 ..Default::default()
1425 };
1426 assert_matches!(
1427 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.disassoc_conf(&disassoc_conf)),
1428 Poll::Ready(Ok(()))
1429 );
1430 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1431
1432 if mac_role == fidl_common::WlanMacRole::Client {
1433 assert_matches!(
1434 h.driver_calls.try_next(),
1435 Ok(Some(DriverCall::OnLinkStateChanged { req })) =>{
1436 assert_eq!(req.online, Some(false));
1437 }
1438 );
1439 } else {
1440 assert_matches!(h.driver_calls.try_next(), Err(_));
1441 }
1442
1443 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1444 let conf = assert_matches!(event, fidl_mlme::MlmeEvent::DisassociateConf { resp } => resp);
1445 assert_eq!(conf, fidl_mlme::DisassociateConfirm { status: 1 });
1446 }
1447
1448 #[test_case(fidl_common::WlanMacRole::Client; "client")]
1449 #[test_case(fidl_common::WlanMacRole::Ap; "ap")]
1450 #[fuchsia::test(add_test_attr = false)]
1451 fn test_disassoc_ind(mac_role: fidl_common::WlanMacRole) {
1452 let (mut h, mut test_fut) =
1453 TestHelper::set_up_with_link_state(fidl_mlme::ControlledPortState::Open);
1454 h.fake_device.lock().query_device_info_mock.as_mut().unwrap().role = Some(mac_role);
1455 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1456
1457 let disassoc_ind = fidl_fullmac::WlanFullmacImplIfcDisassocIndRequest {
1458 peer_sta_address: Some([1u8; 6]),
1459 reason_code: Some(fidl_ieee80211::ReasonCode::LeavingNetworkDeauth),
1460 locally_initiated: Some(true),
1461 ..Default::default()
1462 };
1463 assert_matches!(
1464 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.disassoc_ind(&disassoc_ind)),
1465 Poll::Ready(Ok(()))
1466 );
1467 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1468
1469 if mac_role == fidl_common::WlanMacRole::Client {
1470 assert_matches!(
1471 h.driver_calls.try_next(),
1472 Ok(Some(DriverCall::OnLinkStateChanged { req })) =>{
1473 assert_eq!(req.online, Some(false));
1474 }
1475 );
1476 } else {
1477 assert_matches!(h.driver_calls.try_next(), Err(_));
1478 }
1479
1480 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1481 let ind = assert_matches!(event, fidl_mlme::MlmeEvent::DisassociateInd { ind } => ind);
1482 assert_eq!(
1483 ind,
1484 fidl_mlme::DisassociateIndication {
1485 peer_sta_address: [1u8; 6],
1486 reason_code: fidl_ieee80211::ReasonCode::LeavingNetworkDeauth,
1487 locally_initiated: true,
1488 }
1489 );
1490 }
1491
1492 #[test_case(fidl_fullmac::StartResult::Success, true, fidl_mlme::StartResultCode::Success; "success start result")]
1493 #[test_case(fidl_fullmac::StartResult::BssAlreadyStartedOrJoined, false, fidl_mlme::StartResultCode::BssAlreadyStartedOrJoined; "other start result")]
1494 #[fuchsia::test(add_test_attr = false)]
1495 fn test_start_conf(
1496 start_result: fidl_fullmac::StartResult,
1497 expected_link_state_changed: bool,
1498 expected_fidl_result_code: fidl_mlme::StartResultCode,
1499 ) {
1500 let (mut h, mut test_fut) = TestHelper::set_up();
1501 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1502
1503 let start_conf = fidl_fullmac::WlanFullmacImplIfcStartConfRequest {
1504 result_code: Some(start_result),
1505 ..Default::default()
1506 };
1507 assert_matches!(
1508 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.start_conf(&start_conf)),
1509 Poll::Ready(Ok(()))
1510 );
1511 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1512
1513 if expected_link_state_changed {
1514 assert_matches!(
1515 h.driver_calls.try_next(),
1516 Ok(Some(DriverCall::OnLinkStateChanged { req }))=>{
1517 assert_eq!(req.online, Some(true));
1518 }
1519 );
1520 } else {
1521 assert_matches!(h.driver_calls.try_next(), Err(_));
1522 }
1523
1524 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1525 let conf = assert_matches!(event, fidl_mlme::MlmeEvent::StartConf { resp } => resp);
1526 assert_eq!(conf, fidl_mlme::StartConfirm { result_code: expected_fidl_result_code });
1527 }
1528
1529 #[test]
1530 fn test_stop_conf() {
1531 let (mut h, mut test_fut) = TestHelper::set_up();
1532 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1533
1534 let stop_conf = fidl_fullmac::WlanFullmacImplIfcStopConfRequest {
1535 result_code: Some(fidl_fullmac::StopResult::Success),
1536 ..Default::default()
1537 };
1538 assert_matches!(
1539 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.stop_conf(&stop_conf)),
1540 Poll::Ready(Ok(()))
1541 );
1542 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1543
1544 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1545 let conf = assert_matches!(event, fidl_mlme::MlmeEvent::StopConf { resp } => resp);
1546 assert_eq!(
1547 conf,
1548 fidl_mlme::StopConfirm { result_code: fidl_mlme::StopResultCode::Success }
1549 );
1550 }
1551
1552 #[test]
1553 fn test_eapol_conf() {
1554 let (mut h, mut test_fut) = TestHelper::set_up();
1555 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1556
1557 let eapol_conf = fidl_fullmac::WlanFullmacImplIfcEapolConfRequest {
1558 result_code: Some(fidl_fullmac::EapolTxResult::Success),
1559 dst_addr: Some([1u8; 6]),
1560 ..Default::default()
1561 };
1562 assert_matches!(
1563 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.eapol_conf(&eapol_conf)),
1564 Poll::Ready(Ok(()))
1565 );
1566 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1567
1568 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1569 let conf = assert_matches!(event, fidl_mlme::MlmeEvent::EapolConf { resp } => resp);
1570 assert_eq!(
1571 conf,
1572 fidl_mlme::EapolConfirm {
1573 result_code: fidl_mlme::EapolResultCode::Success,
1574 dst_addr: [1u8; 6],
1575 }
1576 );
1577 }
1578
1579 #[test]
1580 fn test_on_channel_switch() {
1581 let (mut h, mut test_fut) = TestHelper::set_up();
1582 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1583
1584 let channel_switch_info = fidl_fullmac::WlanFullmacChannelSwitchInfo { new_channel: 9 };
1585 assert_matches!(
1586 h.exec.run_until_stalled(
1587 &mut h.fullmac_ifc_proxy.on_channel_switch(&channel_switch_info)
1588 ),
1589 Poll::Ready(Ok(()))
1590 );
1591 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1592
1593 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1594 let info = assert_matches!(event, fidl_mlme::MlmeEvent::OnChannelSwitched { info } => info);
1595 assert_eq!(info, fidl_internal::ChannelSwitchInfo { new_channel: 9 });
1596 }
1597
1598 #[test]
1599 fn test_roam_start_ind() {
1600 let (mut h, mut test_fut) =
1601 TestHelper::set_up_with_link_state(fidl_mlme::ControlledPortState::Open);
1602 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1603
1604 let selected_bss = create_bss_descriptions();
1605 let roam_start_ind = fidl_fullmac::WlanFullmacImplIfcRoamStartIndRequest {
1606 selected_bssid: Some(selected_bss.bssid.clone()),
1607 selected_bss: Some(selected_bss.clone()),
1608 original_association_maintained: Some(false),
1609 ..Default::default()
1610 };
1611 assert_matches!(
1612 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.roam_start_ind(&roam_start_ind)),
1613 Poll::Ready(Ok(()))
1614 );
1615 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1616
1617 assert_matches!(
1619 h.driver_calls.try_next(),
1620 Ok(Some(DriverCall::OnLinkStateChanged { req }))=>{
1621 assert_eq!(req.online, Some(false));
1622 }
1623 );
1624
1625 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1626 let ind = assert_matches!(event, fidl_mlme::MlmeEvent::RoamStartInd { ind } => ind);
1627
1628 assert_eq!(
1630 ind,
1631 fidl_mlme::RoamStartIndication {
1632 selected_bssid: selected_bss.bssid,
1633 selected_bss,
1634 original_association_maintained: false,
1635 }
1636 );
1637 }
1638
1639 #[test]
1640 fn test_roam_req() {
1641 let (mut h, mut test_fut) =
1642 TestHelper::set_up_with_link_state(fidl_mlme::ControlledPortState::Open);
1643
1644 let selected_bss = create_bss_descriptions();
1645 let roam_req = wlan_sme::MlmeRequest::Roam(fidl_mlme::RoamRequest {
1646 selected_bss: selected_bss.clone(),
1647 });
1648
1649 h.mlme_request_sender.unbounded_send(roam_req).expect("sending RoamReq should succeed");
1650 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1651
1652 assert_matches!(
1654 h.driver_calls.try_next(),
1655 Ok(Some(DriverCall::OnLinkStateChanged { req })) => {
1656 assert_eq!(req.online, Some(false));
1657 }
1658 );
1659 assert_matches!(h.driver_calls.try_next(), Ok(Some(DriverCall::RoamReq { req })) => {
1660 assert_eq!(selected_bss, req.selected_bss.clone().unwrap());
1661 });
1662 }
1663
1664 #[test]
1665 fn test_roam_result_ind() {
1666 let (mut h, mut test_fut) = TestHelper::set_up();
1667 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1668
1669 let selected_bss = create_bss_descriptions();
1670 let original_association_maintained = false;
1671 let target_bss_authenticated = true;
1672 let association_id = 42;
1673 let association_ies = Vec::new();
1674
1675 let roam_result_ind = fidl_fullmac::WlanFullmacImplIfcRoamResultIndRequest {
1676 selected_bssid: Some(selected_bss.bssid.clone()),
1677 status_code: Some(fidl_ieee80211::StatusCode::Success),
1678 original_association_maintained: Some(original_association_maintained),
1679 target_bss_authenticated: Some(target_bss_authenticated),
1680 association_id: Some(association_id),
1681 association_ies: Some(association_ies.clone()),
1682 ..Default::default()
1683 };
1684
1685 assert_matches!(
1686 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.roam_result_ind(&roam_result_ind)),
1687 Poll::Ready(Ok(()))
1688 );
1689 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1690
1691 assert_matches!(
1693 h.driver_calls.try_next(),
1694 Ok(Some(DriverCall::OnLinkStateChanged { req }))=>{
1695 assert_eq!(req.online, Some(true));
1696 }
1697 );
1698
1699 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1700 let ind = assert_matches!(event, fidl_mlme::MlmeEvent::RoamResultInd { ind } => ind);
1701
1702 assert_eq!(
1704 ind,
1705 fidl_mlme::RoamResultIndication {
1706 selected_bssid: selected_bss.bssid,
1707 status_code: fidl_ieee80211::StatusCode::Success,
1708 original_association_maintained,
1709 target_bss_authenticated,
1710 association_id,
1711 association_ies,
1712 }
1713 );
1714 }
1715
1716 #[test]
1717 fn test_roam_conf() {
1718 let (mut h, mut test_fut) = TestHelper::set_up();
1719 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1720
1721 let selected_bss = create_bss_descriptions();
1722 let original_association_maintained = false;
1723 let target_bss_authenticated = true;
1724 let association_id = 42;
1725 let association_ies = Vec::new();
1726
1727 let roam_conf = fidl_fullmac::WlanFullmacImplIfcRoamConfRequest {
1728 selected_bssid: Some(selected_bss.bssid.clone()),
1729 status_code: Some(fidl_ieee80211::StatusCode::Success),
1730 original_association_maintained: Some(original_association_maintained),
1731 target_bss_authenticated: Some(target_bss_authenticated),
1732 association_id: Some(association_id),
1733 association_ies: Some(association_ies.clone()),
1734 ..Default::default()
1735 };
1736
1737 assert_matches!(
1738 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.roam_conf(&roam_conf)),
1739 Poll::Ready(Ok(()))
1740 );
1741 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1742
1743 assert_matches!(
1745 h.driver_calls.try_next(),
1746 Ok(Some(DriverCall::OnLinkStateChanged { req })) => {
1747 assert_eq!(req.online, Some(true));
1748 }
1749 );
1750
1751 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1752 let conf = assert_matches!(event, fidl_mlme::MlmeEvent::RoamConf { conf } => conf);
1753
1754 assert_eq!(
1756 conf,
1757 fidl_mlme::RoamConfirm {
1758 selected_bssid: selected_bss.bssid,
1759 status_code: fidl_ieee80211::StatusCode::Success,
1760 original_association_maintained,
1761 target_bss_authenticated,
1762 association_id,
1763 association_ies,
1764 }
1765 );
1766 }
1767
1768 #[test]
1769 fn test_signal_report() {
1770 let (mut h, mut test_fut) = TestHelper::set_up();
1771 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1772
1773 let signal_report_ind =
1774 fidl_fullmac::WlanFullmacSignalReportIndication { rssi_dbm: 1, snr_db: 2 };
1775 assert_matches!(
1776 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.signal_report(&signal_report_ind)),
1777 Poll::Ready(Ok(()))
1778 );
1779 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1780
1781 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1782 let ind = assert_matches!(event, fidl_mlme::MlmeEvent::SignalReport { ind } => ind);
1783 assert_eq!(ind, fidl_internal::SignalReportIndication { rssi_dbm: 1, snr_db: 2 });
1784 }
1785
1786 #[test]
1787 fn test_eapol_ind() {
1788 let (mut h, mut test_fut) = TestHelper::set_up();
1789 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1790
1791 let eapol_ind = fidl_fullmac::WlanFullmacImplIfcEapolIndRequest {
1792 src_addr: Some([1u8; 6]),
1793 dst_addr: Some([2u8; 6]),
1794 data: Some(vec![3u8; 4]),
1795 ..Default::default()
1796 };
1797 assert_matches!(
1798 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.eapol_ind(&eapol_ind)),
1799 Poll::Ready(Ok(()))
1800 );
1801 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1802
1803 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1804 let ind = assert_matches!(event, fidl_mlme::MlmeEvent::EapolInd { ind } => ind);
1805 assert_eq!(
1806 ind,
1807 fidl_mlme::EapolIndication {
1808 src_addr: [1u8; 6],
1809 dst_addr: [2u8; 6],
1810 data: vec![3u8; 4],
1811 }
1812 );
1813 }
1814
1815 #[test]
1816 fn test_on_pmk_available() {
1817 let (mut h, mut test_fut) = TestHelper::set_up();
1818 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1819
1820 let pmk_info = fidl_fullmac::WlanFullmacImplIfcOnPmkAvailableRequest {
1821 pmk: Some(vec![1u8; 2]),
1822 pmkid: Some(vec![3u8; 4]),
1823 ..Default::default()
1824 };
1825 assert_matches!(
1826 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.on_pmk_available(&pmk_info)),
1827 Poll::Ready(Ok(()))
1828 );
1829 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1830
1831 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1832 let info = assert_matches!(event, fidl_mlme::MlmeEvent::OnPmkAvailable { info } => info);
1833 assert_eq!(info, fidl_mlme::PmkInfo { pmk: vec![1u8; 2], pmkid: vec![3u8; 4] });
1834 }
1835
1836 #[test]
1837 fn test_sae_handshake_ind() {
1838 let (mut h, mut test_fut) = TestHelper::set_up();
1839 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1840
1841 let sae_handshake_ind = fidl_fullmac::WlanFullmacImplIfcSaeHandshakeIndRequest {
1842 peer_sta_address: Some([1u8; 6]),
1843 ..Default::default()
1844 };
1845 assert_matches!(
1846 h.exec
1847 .run_until_stalled(&mut h.fullmac_ifc_proxy.sae_handshake_ind(&sae_handshake_ind)),
1848 Poll::Ready(Ok(()))
1849 );
1850 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1851
1852 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1853 let ind = assert_matches!(event, fidl_mlme::MlmeEvent::OnSaeHandshakeInd { ind } => ind);
1854 assert_eq!(ind, fidl_mlme::SaeHandshakeIndication { peer_sta_address: [1u8; 6] });
1855 }
1856
1857 #[test]
1858 fn test_sae_frame_rx() {
1859 let (mut h, mut test_fut) = TestHelper::set_up();
1860 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1861
1862 let sae_frame = fidl_fullmac::SaeFrame {
1863 peer_sta_address: Some([1u8; 6]),
1864 status_code: Some(fidl_ieee80211::StatusCode::Success),
1865 seq_num: Some(2),
1866 sae_fields: Some(vec![3u8; 4]),
1867 ..Default::default()
1868 };
1869 assert_matches!(
1870 h.exec.run_until_stalled(&mut h.fullmac_ifc_proxy.sae_frame_rx(&sae_frame)),
1871 Poll::Ready(Ok(()))
1872 );
1873 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1874
1875 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1876 let frame = assert_matches!(event, fidl_mlme::MlmeEvent::OnSaeFrameRx { frame } => frame);
1877 assert_eq!(
1878 frame,
1879 fidl_mlme::SaeFrame {
1880 peer_sta_address: [1u8; 6],
1881 status_code: fidl_ieee80211::StatusCode::Success,
1882 seq_num: 2,
1883 sae_fields: vec![3u8; 4],
1884 }
1885 );
1886 }
1887
1888 #[test]
1889 fn test_on_wmm_status_resp() {
1890 let (mut h, mut test_fut) = TestHelper::set_up();
1891 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1892
1893 let status = zx::sys::ZX_OK;
1894 let wmm_params = fidl_common::WlanWmmParameters {
1895 apsd: true,
1896 ac_be_params: fidl_common::WlanWmmAccessCategoryParameters {
1897 ecw_min: 1,
1898 ecw_max: 2,
1899 aifsn: 3,
1900 txop_limit: 4,
1901 acm: true,
1902 },
1903 ac_bk_params: fidl_common::WlanWmmAccessCategoryParameters {
1904 ecw_min: 5,
1905 ecw_max: 6,
1906 aifsn: 7,
1907 txop_limit: 8,
1908 acm: false,
1909 },
1910 ac_vi_params: fidl_common::WlanWmmAccessCategoryParameters {
1911 ecw_min: 9,
1912 ecw_max: 10,
1913 aifsn: 11,
1914 txop_limit: 12,
1915 acm: true,
1916 },
1917 ac_vo_params: fidl_common::WlanWmmAccessCategoryParameters {
1918 ecw_min: 13,
1919 ecw_max: 14,
1920 aifsn: 15,
1921 txop_limit: 16,
1922 acm: false,
1923 },
1924 };
1925 assert_matches!(
1926 h.exec.run_until_stalled(
1927 &mut h.fullmac_ifc_proxy.on_wmm_status_resp(status, &wmm_params)
1928 ),
1929 Poll::Ready(Ok(()))
1930 );
1931 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
1932
1933 let event = assert_matches!(h.mlme_event_receiver.try_next(), Ok(Some(ev)) => ev);
1934 let (status, resp) = assert_matches!(event, fidl_mlme::MlmeEvent::OnWmmStatusResp { status, resp } => (status, resp));
1935 assert_eq!(status, zx::sys::ZX_OK);
1936 assert_eq!(
1937 resp,
1938 fidl_internal::WmmStatusResponse {
1939 apsd: true,
1940 ac_be_params: fidl_internal::WmmAcParams {
1941 ecw_min: 1,
1942 ecw_max: 2,
1943 aifsn: 3,
1944 txop_limit: 4,
1945 acm: true,
1946 },
1947 ac_bk_params: fidl_internal::WmmAcParams {
1948 ecw_min: 5,
1949 ecw_max: 6,
1950 aifsn: 7,
1951 txop_limit: 8,
1952 acm: false,
1953 },
1954 ac_vi_params: fidl_internal::WmmAcParams {
1955 ecw_min: 9,
1956 ecw_max: 10,
1957 aifsn: 11,
1958 txop_limit: 12,
1959 acm: true,
1960 },
1961 ac_vo_params: fidl_internal::WmmAcParams {
1962 ecw_min: 13,
1963 ecw_max: 14,
1964 aifsn: 15,
1965 txop_limit: 16,
1966 acm: false,
1967 },
1968 }
1969 );
1970 }
1971
1972 struct TestHelper {
1973 fake_device: Arc<Mutex<FakeFullmacDeviceMocks>>,
1974 mlme_request_sender: mpsc::UnboundedSender<wlan_sme::MlmeRequest>,
1975 fullmac_ifc_proxy: fidl_fullmac::WlanFullmacImplIfcProxy,
1976 mlme_event_receiver: mpsc::UnboundedReceiver<fidl_mlme::MlmeEvent>,
1977 driver_calls: mpsc::UnboundedReceiver<DriverCall>,
1978 exec: fasync::TestExecutor,
1979 }
1980
1981 impl TestHelper {
1982 pub fn set_up() -> (Self, Pin<Box<impl Future<Output = Result<(), anyhow::Error>>>>) {
1984 Self::set_up_with_link_state(fidl_mlme::ControlledPortState::Closed)
1985 }
1986
1987 pub fn set_up_with_link_state(
1990 device_link_state: fidl_mlme::ControlledPortState,
1991 ) -> (Self, Pin<Box<impl Future<Output = Result<(), anyhow::Error>>>>) {
1992 let exec = fasync::TestExecutor::new();
1993
1994 let (fake_device, driver_call_receiver) = FakeFullmacDevice::new();
1995 let (mlme_request_sender, mlme_request_stream) = mpsc::unbounded();
1996 let (mlme_event_sender, mlme_event_receiver) = mpsc::unbounded();
1997 let mlme_event_sink = UnboundedSink::new(mlme_event_sender);
1998
1999 let (driver_event_sender, driver_event_stream) = mpsc::unbounded();
2000 let driver_event_sink = FullmacDriverEventSink(UnboundedSink::new(driver_event_sender));
2001
2002 let (fullmac_ifc_proxy, fullmac_ifc_request_stream) =
2003 fidl::endpoints::create_proxy_and_stream::<fidl_fullmac::WlanFullmacImplIfcMarker>(
2004 );
2005
2006 let mocks = fake_device.mocks.clone();
2007 let main_loop = MlmeMainLoop {
2008 device: fake_device,
2009 mlme_request_stream,
2010 mlme_event_sink,
2011 driver_event_stream,
2012 is_bss_protected: false,
2013 device_link_state,
2014 };
2015
2016 let test_fut = Box::pin(main_loop.serve(fullmac_ifc_request_stream, driver_event_sink));
2017
2018 let test_helper = TestHelper {
2019 fake_device: mocks,
2020 mlme_request_sender,
2021 fullmac_ifc_proxy,
2022 mlme_event_receiver,
2023 driver_calls: driver_call_receiver,
2024 exec,
2025 };
2026 (test_helper, test_fut)
2027 }
2028 }
2029}