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