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