1#![warn(clippy::indexing_slicing)]
7#![cfg_attr(test, allow(clippy::indexing_slicing))]
8#![warn(clippy::unwrap_used)]
9#![cfg_attr(test, allow(clippy::unwrap_used))]
10#![warn(clippy::expect_used)]
11#![cfg_attr(test, allow(clippy::expect_used))]
12#![warn(clippy::unreachable)]
13#![cfg_attr(test, allow(clippy::unreachable))]
14#![warn(clippy::unimplemented)]
15#![cfg_attr(test, allow(clippy::unimplemented))]
16
17mod convert;
18pub mod device;
19mod logger;
20mod mlme_main_loop;
21mod wlan_fullmac_impl_ifc_request_handler;
22
23use crate::convert::fullmac_to_mlme;
24use crate::device::DeviceOps;
25use crate::mlme_main_loop::create_mlme_main_loop;
26use anyhow::bail;
27use fidl_fuchsia_wlan_common as fidl_common;
28use fidl_fuchsia_wlan_internal as fidl_internal;
29use fidl_fuchsia_wlan_mlme as fidl_mlme;
30use fidl_fuchsia_wlan_sme as fidl_sme;
31use fuchsia_async as fasync;
32use fuchsia_inspect::Inspector;
33use futures::StreamExt;
34use futures::channel::{mpsc, oneshot};
35use futures::future::BoxFuture;
36use log::{error, info, warn};
37use std::sync::Arc;
38use wlan_common::sink::UnboundedSink;
39use wlan_ffi_transport::completers::Completer;
40use wlan_power_manager::SyncPowerManager;
41use wlan_sme::serve::create_sme;
42
43#[derive(thiserror::Error, Debug)]
44pub enum FullmacMlmeError {
45 #[error("device.start failed: {0}")]
46 DeviceStartFailed(zx::Status),
47 #[error("Failed to get usme bootstrap stream: {0}")]
48 FailedToGetUsmeBootstrapStream(fidl::Error),
49 #[error("USME bootstrap stream failed: {0}")]
50 UsmeBootstrapStreamFailed(fidl::Error),
51 #[error("USME bootstrap stream terminated")]
52 UsmeBootstrapStreamTerminated,
53 #[error("Failed to duplicate inspect VMO")]
54 FailedToDuplicateInspectVmo,
55 #[error("Failed to respond to usme bootstrap request: {0}")]
56 FailedToRespondToUsmeBootstrapRequest(fidl::Error),
57 #[error("Failed to get generic SME stream: {0}")]
58 FailedToGetGenericSmeStream(fidl::Error),
59 #[error("Invalid MAC implementation type: {0:?}")]
60 InvalidMacImplementationType(fidl_common::MacImplementationType),
61 #[error("Invalid data plane type: {0:?}")]
62 InvalidDataPlaneType(fidl_common::DataPlaneType),
63 #[error("Failed to query vendor driver: {0:?}")]
64 FailedToQueryVendorDriver(anyhow::Error),
65 #[error("Failed to convert query from vendor driver: {0:?}")]
66 FailedToConvertVendorDriverQuery(anyhow::Error),
67 #[error("Failed to create sme: {0}")]
68 FailedToCreateSme(anyhow::Error),
69 #[error("Failed to create WlanFullmacImplIfcRequestStream: {0}")]
70 FailedToCreateIfcRequestStream(fidl::Error),
71}
72
73#[derive(Debug)]
74struct FullmacDriverEventSink(pub UnboundedSink<FullmacDriverEvent>);
75
76#[derive(Debug)]
77enum FullmacDriverEvent {
78 Stop,
79 OnScanResult { result: fidl_mlme::ScanResult },
80 OnScanEnd { end: fidl_mlme::ScanEnd },
81 OnScheduledScanMatchesAvailable { txn_id: u64 },
82 OnScheduledScanStoppedByFirmware { txn_id: u64 },
83 ConnectConf { resp: fidl_mlme::ConnectConfirm },
84 RoamConf { conf: fidl_mlme::RoamConfirm },
85 RoamStartInd { ind: fidl_mlme::RoamStartIndication },
86 RoamResultInd { ind: fidl_mlme::RoamResultIndication },
87 AuthInd { ind: fidl_mlme::AuthenticateIndication },
88 DeauthConf { resp: fidl_mlme::DeauthenticateConfirm },
89 DeauthInd { ind: fidl_mlme::DeauthenticateIndication },
90 AssocInd { ind: fidl_mlme::AssociateIndication },
91 DisassocConf { resp: fidl_mlme::DisassociateConfirm },
92 DisassocInd { ind: fidl_mlme::DisassociateIndication },
93 StartConf { resp: fidl_mlme::StartConfirm },
94 StopConf { resp: fidl_mlme::StopConfirm },
95 EapolConf { resp: fidl_mlme::EapolConfirm },
96 OnChannelSwitch { resp: fidl_internal::ChannelSwitchInfo },
97 SignalReport { ind: fidl_internal::SignalReportIndication },
98 OnRssiThresholdBreached { cur_rssi_dbm: i8 },
99 EapolInd { ind: fidl_mlme::EapolIndication },
100 OnPmkAvailable { info: fidl_mlme::PmkInfo },
101 SaeHandshakeInd { ind: fidl_mlme::SaeHandshakeIndication },
102 SaeFrameRx { frame: fidl_mlme::SaeFrame },
103 OnWmmStatusResp { status: i32, resp: fidl_internal::WmmStatusResponse },
104}
105
106enum DriverState {
107 Running,
108 Stopping,
109}
110
111pub struct FullmacMlmeHandle {
112 driver_event_sender: mpsc::UnboundedSender<FullmacDriverEvent>,
113 mlme_loop_join_handle: Option<std::thread::JoinHandle<()>>,
114 stop_requested: bool,
115}
116
117impl FullmacMlmeHandle {
118 pub fn request_stop(&mut self) {
119 info!("Requesting MLME stop...");
120 if let Err(e) = self.driver_event_sender.unbounded_send(FullmacDriverEvent::Stop) {
121 error!("Cannot signal MLME event loop thread: {}", e);
122 } else {
123 self.stop_requested = true;
129 }
130 }
131
132 pub fn delete(mut self) {
133 if !self.stop_requested {
134 warn!("Called delete on FullmacMlmeHandle before calling stop.");
135 self.request_stop()
136 }
137
138 match self.mlme_loop_join_handle.take() {
139 Some(join_handle) => {
140 if let Err(e) = join_handle.join() {
141 error!("MLME event loop thread panicked: {:?}", e);
142 }
143 }
144 None => warn!("Called stop on already stopped MLME"),
145 }
146 info!("MLME main loop thread has shutdown.");
147 }
148}
149
150const INSPECT_VMO_SIZE_BYTES: usize = 1000 * 1024;
151
152pub async fn start_and_serve_on_separate_thread<F, D: DeviceOps + Send + 'static>(
160 device: D,
161 shutdown_completer: Completer<F>,
162 power_manager: Arc<dyn SyncPowerManager>,
163) -> anyhow::Result<FullmacMlmeHandle>
164where
165 F: FnOnce(zx::sys::zx_status_t) + 'static,
166{
167 logger::init();
168
169 let (driver_event_sender, driver_event_stream) = mpsc::unbounded();
170 let driver_event_sender_clone = driver_event_sender.clone();
171 let inspector =
172 Inspector::new(fuchsia_inspect::InspectorConfig::default().size(INSPECT_VMO_SIZE_BYTES));
173
174 let (startup_sender, startup_receiver) = oneshot::channel();
175 let mlme_loop_join_handle = std::thread::spawn(move || {
176 let mut executor = fasync::SendExecutorBuilder::new().num_threads(2).build();
180
181 info!("Starting WLAN MLME main loop");
182 let future = start_and_serve(
183 device,
184 driver_event_sender_clone,
185 driver_event_stream,
186 inspector,
187 startup_sender,
188 power_manager,
189 );
190 let result = executor.run(future);
191 shutdown_completer.reply(result);
192 });
193
194 match startup_receiver.await {
195 Ok(Ok(())) => (),
196 Ok(Err(err)) => bail!(
197 "MLME failed to start with error {}. MLME main loop returned {:?}.",
198 err,
199 mlme_loop_join_handle.join()
200 ),
201 Err(oneshot::Canceled) => bail!(
202 "MLME thread dropped startup_sender. MLME main loop returned {:?}",
203 mlme_loop_join_handle.join()
204 ),
205 };
206
207 Ok(FullmacMlmeHandle {
208 driver_event_sender,
209 mlme_loop_join_handle: Some(mlme_loop_join_handle),
210 stop_requested: false,
211 })
212}
213
214struct StartedDriver {
218 mlme_main_loop_fut: BoxFuture<'static, anyhow::Result<()>>,
219 sme_fut: BoxFuture<'static, anyhow::Result<()>>,
220}
221
222async fn start_and_serve<D: DeviceOps + Send + 'static>(
234 device: D,
235 driver_event_sender: mpsc::UnboundedSender<FullmacDriverEvent>,
236 driver_event_stream: mpsc::UnboundedReceiver<FullmacDriverEvent>,
237 inspector: Inspector,
238 startup_sender: oneshot::Sender<Result<(), FullmacMlmeError>>,
239 power_manager: Arc<dyn SyncPowerManager>,
240) -> Result<(), zx::Status> {
241 let StartedDriver { mlme_main_loop_fut, sme_fut } =
242 match start(device, driver_event_stream, driver_event_sender, inspector, power_manager)
243 .await
244 {
245 Ok(initialized_mlme) => {
246 if let Err(e) = startup_sender.send(Ok(())) {
247 error!("Failed to send startup response: {:?}", e);
248 return Err(zx::Status::INTERNAL);
249 }
250 initialized_mlme
251 }
252 Err(e) => {
253 if let Err(e) = startup_sender.send(Err(e)) {
254 error!("Failed to send startup response: {:?}", e);
255 }
256 return Err(zx::Status::INTERNAL);
257 }
258 };
259
260 match futures::try_join!(mlme_main_loop_fut, sme_fut) {
261 Ok(_) => {
262 info!("MLME and/or SME event loop exited gracefully");
263 Ok(())
264 }
265 Err(e) => {
266 error!("MLME and/or SME event loop exited with error: {:?}", e);
267 Err(zx::Status::INTERNAL)
268 }
269 }
270}
271
272async fn start<D: DeviceOps + Send + 'static>(
282 mut device: D,
283 driver_event_stream: mpsc::UnboundedReceiver<FullmacDriverEvent>,
284 driver_event_sender: mpsc::UnboundedSender<FullmacDriverEvent>,
285 inspector: Inspector,
286 power_manager: Arc<dyn SyncPowerManager>,
287) -> Result<StartedDriver, FullmacMlmeError> {
288 let (fullmac_ifc_client_end, fullmac_ifc_request_stream) =
289 fidl::endpoints::create_request_stream();
290
291 let usme_bootstrap_protocol_channel =
292 device.init(fullmac_ifc_client_end).map_err(FullmacMlmeError::DeviceStartFailed)?;
293
294 let server = fidl::endpoints::ServerEnd::<fidl_sme::UsmeBootstrapMarker>::new(
295 usme_bootstrap_protocol_channel,
296 );
297
298 let mut usme_bootstrap_stream = server.into_stream();
299
300 let fidl_sme::UsmeBootstrapRequest::Start {
301 generic_sme_server,
302 legacy_privacy_support,
303 responder,
304 ..
305 } = usme_bootstrap_stream
306 .next()
307 .await
308 .ok_or(FullmacMlmeError::UsmeBootstrapStreamTerminated)?
309 .map_err(FullmacMlmeError::UsmeBootstrapStreamFailed)?;
310
311 let inspect_vmo =
312 inspector.duplicate_vmo().ok_or(FullmacMlmeError::FailedToDuplicateInspectVmo)?;
313
314 responder.send(inspect_vmo).map_err(FullmacMlmeError::FailedToRespondToUsmeBootstrapRequest)?;
315
316 let generic_sme_stream = generic_sme_server.into_stream();
317
318 let cfg = wlan_sme::Config {
320 wep_supported: legacy_privacy_support.wep_supported,
321 wpa1_supported: legacy_privacy_support.wpa1_supported,
322 };
323
324 let (mlme_event_sender, mlme_event_receiver) = mpsc::unbounded();
325 let mlme_event_sink = UnboundedSink::new(mlme_event_sender);
326
327 let device_info =
328 device.query_device_info().map_err(FullmacMlmeError::FailedToQueryVendorDriver)?;
329 let device_info = fullmac_to_mlme::convert_device_info(device_info)
330 .map_err(FullmacMlmeError::FailedToConvertVendorDriverQuery)?;
331
332 let security_support =
333 device.query_security_support().map_err(FullmacMlmeError::FailedToQueryVendorDriver)?;
334
335 let spectrum_management_support = device
336 .query_spectrum_management_support()
337 .map_err(FullmacMlmeError::FailedToQueryVendorDriver)?;
338
339 let (mlme_request_stream, sme_fut) = create_sme(
340 cfg.into(),
341 mlme_event_receiver,
342 &device_info,
343 security_support,
344 spectrum_management_support,
345 inspector,
346 generic_sme_stream,
347 power_manager,
348 )
349 .map_err(FullmacMlmeError::FailedToCreateSme)?;
350
351 let driver_event_sink = FullmacDriverEventSink(UnboundedSink::new(driver_event_sender));
352 let mlme_main_loop_fut = create_mlme_main_loop(
353 device,
354 mlme_request_stream,
355 mlme_event_sink,
356 driver_event_stream,
357 driver_event_sink,
358 fullmac_ifc_request_stream,
359 );
360
361 Ok(StartedDriver { mlme_main_loop_fut, sme_fut })
362}
363
364#[cfg(test)]
365mod tests {
366 use super::*;
367 use crate::device::test_utils::{DriverCall, FakeFullmacDevice, FakeFullmacDeviceMocks};
368 use assert_matches::assert_matches;
369 use fuchsia_async as fasync;
370 use fuchsia_sync::Mutex;
371 use futures::Future;
372 use futures::task::Poll;
373 use std::pin::Pin;
374 use std::sync::Arc;
375
376 #[test]
377 fn test_happy_path() {
378 let (mut h, mut test_fut) = TestHelper::set_up();
379 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
380
381 let startup_result =
382 assert_matches!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
383 assert_matches!(startup_result, Ok(()));
384
385 let (client_sme_proxy, client_sme_server) =
386 fidl::endpoints::create_proxy::<fidl_sme::ClientSmeMarker>();
387
388 let mut client_sme_response_fut =
389 h.generic_sme_proxy.as_ref().unwrap().get_client_sme(client_sme_server);
390 assert_matches!(h.exec.run_until_stalled(&mut client_sme_response_fut), Poll::Pending);
391 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
392 assert_matches!(
393 h.exec.run_until_stalled(&mut client_sme_response_fut),
394 Poll::Ready(Ok(Ok(())))
395 );
396
397 let mut status_fut = client_sme_proxy.status();
398 assert_matches!(h.exec.run_until_stalled(&mut status_fut), Poll::Pending);
399 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
400 let status_result = assert_matches!(h.exec.run_until_stalled(&mut status_fut), Poll::Ready(result) => result);
401 assert_matches!(status_result, Ok(fidl_sme::ClientStatusResponse::Idle(_)));
402 }
403
404 #[test]
405 fn test_mlme_exits_due_to_driver_event() {
406 let (mut h, mut test_fut) = TestHelper::set_up();
407 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
408
409 let startup_result =
410 assert_matches!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
411 assert_matches!(startup_result, Ok(()));
412
413 h.driver_event_sender
414 .unbounded_send(FullmacDriverEvent::Stop)
415 .expect("expect sending driver Stop event to succeed");
416 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Ready(Ok(())));
417 }
418
419 #[test]
420 fn test_mlme_startup_fails_due_to_device_start() {
421 let (mut h, mut test_fut) = TestHelper::set_up();
422 h.fake_device.lock().start_fn_status_mock = Some(zx::sys::ZX_ERR_BAD_STATE);
423 assert_matches!(
424 h.exec.run_until_stalled(&mut test_fut),
425 Poll::Ready(Err(zx::Status::INTERNAL))
426 );
427
428 let startup_result =
429 assert_matches!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
430 assert_matches!(startup_result, Err(FullmacMlmeError::DeviceStartFailed(_)))
431 }
432
433 #[test]
434 fn test_mlme_startup_fails_due_to_usme_bootstrap_terminated() {
435 let bootstrap = false;
436 let (mut h, mut test_fut) = TestHelper::set_up_with_usme_bootstrap(bootstrap);
437 h.usme_bootstrap_proxy.take();
438 assert_matches!(
439 h.exec.run_until_stalled(&mut test_fut),
440 Poll::Ready(Err(zx::Status::INTERNAL))
441 );
442
443 let startup_result =
444 assert_matches!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
445 assert_matches!(startup_result, Err(FullmacMlmeError::UsmeBootstrapStreamTerminated));
446 }
447
448 #[test]
449 fn test_mlme_startup_fails_due_to_query_device_info_error() {
450 let (mut h, mut test_fut) = TestHelper::set_up();
451 h.fake_device.lock().query_device_info_mock = None;
452 assert_matches!(
453 h.exec.run_until_stalled(&mut test_fut),
454 Poll::Ready(Err(zx::Status::INTERNAL))
455 );
456
457 let startup_result =
458 assert_matches!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
459 assert_matches!(startup_result, Err(FullmacMlmeError::FailedToQueryVendorDriver(_)));
460 }
461
462 #[test]
463 fn test_mlme_startup_fails_due_to_query_security_support_error() {
464 let (mut h, mut test_fut) = TestHelper::set_up();
465 h.fake_device.lock().query_security_support_mock = None;
466 assert_matches!(
467 h.exec.run_until_stalled(&mut test_fut),
468 Poll::Ready(Err(zx::Status::INTERNAL))
469 );
470
471 let startup_result =
472 assert_matches!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
473 assert_matches!(startup_result, Err(FullmacMlmeError::FailedToQueryVendorDriver(_)));
474 }
475
476 #[test]
477 fn test_mlme_startup_fails_due_to_query_spectrum_management_support_error() {
478 let (mut h, mut test_fut) = TestHelper::set_up();
479 h.fake_device.lock().query_spectrum_management_support_mock = None;
480 assert_matches!(
481 h.exec.run_until_stalled(&mut test_fut),
482 Poll::Ready(Err(zx::Status::INTERNAL))
483 );
484
485 let startup_result =
486 assert_matches!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
487 assert_matches!(startup_result, Err(FullmacMlmeError::FailedToQueryVendorDriver(_)));
488 }
489
490 #[test]
491 fn test_mlme_startup_fails_due_to_failure_to_convert_query_device_info() {
492 let (mut h, mut test_fut) = TestHelper::set_up();
493 h.fake_device.lock().query_device_info_mock.as_mut().unwrap().role = None;
494 assert_matches!(
495 h.exec.run_until_stalled(&mut test_fut),
496 Poll::Ready(Err(zx::Status::INTERNAL))
497 );
498
499 let startup_result =
500 assert_matches!(h.startup_receiver.try_recv(), Ok(Some(result)) => result);
501 assert_matches!(startup_result, Err(FullmacMlmeError::FailedToConvertVendorDriverQuery(_)));
502 }
503
504 #[test]
505 fn test_mlme_startup_exits_due_to_sme_channel_closure() {
506 let (mut h, mut test_fut) = TestHelper::set_up();
507 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
508 assert_matches!(h.startup_receiver.try_recv(), Ok(Some(Ok(()))));
509
510 std::mem::drop(h.generic_sme_proxy.take());
511 assert_matches!(
512 h.exec.run_until_stalled(&mut test_fut),
513 Poll::Ready(Err(zx::Status::INTERNAL))
514 );
515 }
516
517 #[test]
518 fn test_mlme_startup_exits_due_to_wlan_fullmac_impl_ifc_channel_closure() {
519 let (mut h, mut test_fut) = TestHelper::set_up();
520 assert_matches!(h.exec.run_until_stalled(&mut test_fut), Poll::Pending);
521 assert_matches!(h.startup_receiver.try_recv(), Ok(Some(Ok(()))));
522
523 std::mem::drop(h.fake_device.lock().fullmac_ifc_client_end.take());
524 assert_matches!(
525 h.exec.run_until_stalled(&mut test_fut),
526 Poll::Ready(Err(zx::Status::INTERNAL))
527 );
528 }
529
530 struct TestHelper {
531 fake_device: Arc<Mutex<FakeFullmacDeviceMocks>>,
532 driver_event_sender: mpsc::UnboundedSender<FullmacDriverEvent>,
533 usme_bootstrap_proxy: Option<fidl_sme::UsmeBootstrapProxy>,
534 _usme_bootstrap_result: Option<fidl::client::QueryResponseFut<zx::Vmo>>,
535 generic_sme_proxy: Option<fidl_sme::GenericSmeProxy>,
536 startup_receiver: oneshot::Receiver<Result<(), FullmacMlmeError>>,
537 _driver_calls: mpsc::UnboundedReceiver<DriverCall>,
538 exec: fasync::TestExecutor,
539 }
540
541 impl TestHelper {
542 pub fn set_up() -> (Self, Pin<Box<impl Future<Output = Result<(), zx::Status>>>>) {
543 let bootstrap = true;
544 Self::set_up_with_usme_bootstrap(bootstrap)
545 }
546
547 pub fn set_up_with_usme_bootstrap(
548 bootstrap: bool,
549 ) -> (Self, Pin<Box<impl Future<Output = Result<(), zx::Status>>>>) {
550 let exec = fasync::TestExecutor::new();
551
552 let (mut fake_device, _driver_calls) = FakeFullmacDevice::new();
553 let usme_bootstrap_proxy =
554 fake_device.usme_bootstrap_client_end.take().unwrap().into_proxy();
555
556 let (generic_sme_proxy, generic_sme_server_end) =
557 fidl::endpoints::create_proxy::<fidl_sme::GenericSmeMarker>();
558 let usme_bootstrap_result = if bootstrap {
559 Some(usme_bootstrap_proxy.start(
560 generic_sme_server_end,
561 &fidl_sme::LegacyPrivacySupport { wep_supported: false, wpa1_supported: false },
562 ))
563 } else {
564 None
565 };
566
567 let (driver_event_sender, driver_event_stream) = mpsc::unbounded();
568 let inspector = Inspector::default();
569 let (startup_sender, startup_receiver) = oneshot::channel();
570
571 let mocks = fake_device.mocks.clone();
572
573 let test_fut = Box::pin(start_and_serve(
574 fake_device,
575 driver_event_sender.clone(),
576 driver_event_stream,
577 inspector,
578 startup_sender,
579 Arc::new(()),
580 ));
581
582 let test_helper = TestHelper {
583 fake_device: mocks,
584 driver_event_sender,
585 usme_bootstrap_proxy: Some(usme_bootstrap_proxy),
586 _usme_bootstrap_result: usme_bootstrap_result,
587 generic_sme_proxy: Some(generic_sme_proxy),
588 startup_receiver,
589 _driver_calls,
590 exec,
591 };
592 (test_helper, test_fut)
593 }
594 }
595}