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