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