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
17pub mod ap;
18pub mod client;
19pub mod serve;
20#[cfg(test)]
21pub mod test_utils;
22
23use fidl_fuchsia_wlan_common as fidl_common;
24use fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211;
25use fidl_fuchsia_wlan_mlme::{self as fidl_mlme, MlmeEvent};
26use fidl_fuchsia_wlan_stats as fidl_stats;
27use futures::channel::mpsc;
28use thiserror::Error;
29use wlan_common::sink::UnboundedSink;
30use wlan_common::timer;
31
32#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
33pub struct Config {
34 pub wep_supported: bool,
35 pub wpa1_supported: bool,
36}
37
38impl Config {
39 pub fn with_wep(mut self) -> Self {
40 self.wep_supported = true;
41 self
42 }
43
44 pub fn with_wpa1(mut self) -> Self {
45 self.wpa1_supported = true;
46 self
47 }
48}
49
50#[derive(Debug)]
51pub enum MlmeRequest {
52 Scan(fidl_mlme::ScanRequest),
53 AuthResponse(fidl_mlme::AuthenticateResponse),
54 AssocResponse(fidl_mlme::AssociateResponse),
55 Connect(fidl_mlme::ConnectRequest),
56 Reconnect(fidl_mlme::ReconnectRequest),
57 Roam(fidl_mlme::RoamRequest),
58 Deauthenticate(fidl_mlme::DeauthenticateRequest),
59 Disassociate(fidl_mlme::DisassociateRequest),
60 Eapol(fidl_mlme::EapolRequest),
61 SetKeys(fidl_mlme::SetKeysRequest),
62 SetCtrlPort(fidl_mlme::SetControlledPortRequest),
63 Start(fidl_mlme::StartRequest),
64 Stop(fidl_mlme::StopRequest),
65 GetIfaceStats(responder::Responder<fidl_mlme::GetIfaceStatsResponse>),
66 GetIfaceHistogramStats(responder::Responder<fidl_mlme::GetIfaceHistogramStatsResponse>),
67 GetSignalReport(responder::Responder<Result<fidl_stats::SignalReport, i32>>),
68 ListMinstrelPeers(responder::Responder<fidl_mlme::MinstrelListResponse>),
69 GetMinstrelStats(
70 fidl_mlme::MinstrelStatsRequest,
71 responder::Responder<fidl_mlme::MinstrelStatsResponse>,
72 ),
73 SaeHandshakeResp(fidl_mlme::SaeHandshakeResponse),
74 SaeFrameTx(fidl_mlme::SaeFrame),
75 WmmStatusReq,
76 FinalizeAssociation(fidl_mlme::NegotiatedCapabilities),
77 QueryDeviceInfo(responder::Responder<fidl_mlme::DeviceInfo>),
78 QueryMacSublayerSupport(responder::Responder<fidl_common::MacSublayerSupport>),
79 QuerySecuritySupport(responder::Responder<fidl_common::SecuritySupport>),
80 QuerySpectrumManagementSupport(responder::Responder<fidl_common::SpectrumManagementSupport>),
81 QueryTelemetrySupport(responder::Responder<Result<fidl_stats::TelemetrySupport, i32>>),
82 QueryApfPacketFilterSupport(
83 responder::Responder<Result<fidl_common::ApfPacketFilterSupport, i32>>,
84 ),
85 QueryRssiMonitorSupport(responder::Responder<Result<fidl_common::RssiMonitorSupport, i32>>),
86 SetMacAddress(fidl_ieee80211::MacAddr, responder::Responder<Result<(), i32>>),
87 InstallApfPacketFilter(
88 fidl_mlme::MlmeInstallApfPacketFilterRequest,
89 responder::Responder<Result<(), i32>>,
90 ),
91 ReadApfPacketFilterData(
92 responder::Responder<Result<fidl_mlme::MlmeReadApfPacketFilterDataResponse, i32>>,
93 ),
94 SetApfPacketFilterEnabled(
95 fidl_mlme::MlmeSetApfPacketFilterEnabledRequest,
96 responder::Responder<Result<(), i32>>,
97 ),
98 GetApfPacketFilterEnabled(
99 responder::Responder<Result<fidl_mlme::MlmeGetApfPacketFilterEnabledResponse, i32>>,
100 ),
101 StartScheduledScan(
102 fidl_mlme::MlmeStartScheduledScanRequest,
103 responder::Responder<Result<(), i32>>,
104 ),
105 StopScheduledScan(
106 fidl_mlme::MlmeStopScheduledScanRequest,
107 responder::Responder<Result<(), i32>>,
108 ),
109 GetScheduledScanEnabled(
110 responder::Responder<Result<fidl_mlme::MlmeGetScheduledScanEnabledResponse, i32>>,
111 ),
112 StartRssiMonitor(fidl_mlme::MlmeStartRssiMonitorRequest, responder::Responder<Result<(), i32>>),
113 StopRssiMonitor(responder::Responder<Result<(), i32>>),
114}
115
116impl MlmeRequest {
117 pub fn name(&self) -> &'static str {
118 match self {
119 Self::Scan(_) => "Scan",
120 Self::AuthResponse(_) => "AuthResponse",
121 Self::AssocResponse(_) => "AssocResponse",
122 Self::Connect(_) => "Connect",
123 Self::Reconnect(_) => "Reconnect",
124 Self::Roam(_) => "Roam",
125 Self::Deauthenticate(_) => "Deauthenticate",
126 Self::Disassociate(_) => "Disassociate",
127 Self::Eapol(_) => "Eapol",
128 Self::SetKeys(_) => "SetKeys",
129 Self::SetCtrlPort(_) => "SetCtrlPort",
130 Self::Start(_) => "Start",
131 Self::Stop(_) => "Stop",
132 Self::GetIfaceStats(_) => "GetIfaceStats",
133 Self::GetIfaceHistogramStats(_) => "GetIfaceHistogramStats",
134 Self::StartScheduledScan(..) => "StartScheduledScan",
135 Self::StopScheduledScan(..) => "StopScheduledScan",
136 Self::GetScheduledScanEnabled(_) => "GetScheduledScanEnabled",
137 Self::GetSignalReport(_) => "GetSignalReport",
138 Self::ListMinstrelPeers(_) => "ListMinstrelPeers",
139 Self::GetMinstrelStats(_, _) => "GetMinstrelStats",
140 Self::SaeHandshakeResp(_) => "SaeHandshakeResp",
141 Self::SaeFrameTx(_) => "SaeFrameTx",
142 Self::WmmStatusReq => "WmmStatusReq",
143 Self::FinalizeAssociation(_) => "FinalizeAssociation",
144 Self::QueryDeviceInfo(_) => "QueryDeviceInfo",
145 Self::QueryMacSublayerSupport(_) => "QueryMacSublayerSupport",
146 Self::QuerySecuritySupport(_) => "QuerySecuritySupport",
147 Self::QuerySpectrumManagementSupport(_) => "QuerySpectrumManagementSupport",
148 Self::QueryTelemetrySupport(_) => "QueryTelemetrySupport",
149 Self::QueryApfPacketFilterSupport(_) => "QueryApfPacketFilterSupport",
150 Self::QueryRssiMonitorSupport(_) => "QueryRssiMonitorSupport",
151 Self::SetMacAddress(..) => "SetMacAddress",
152 Self::InstallApfPacketFilter(..) => "InstallApfPacketFilter",
153 Self::ReadApfPacketFilterData(_) => "ReadApfPacketFilterData",
154 Self::SetApfPacketFilterEnabled(..) => "SetApfPacketFilterEnabled",
155 Self::GetApfPacketFilterEnabled(_) => "GetApfPacketFilterEnabled",
156 Self::StartRssiMonitor(..) => "StartRssiMonitor",
157 Self::StopRssiMonitor(_) => "StopRssiMonitor",
158 }
159 }
160}
161
162pub trait Station {
163 type Event;
164
165 fn on_mlme_event(&mut self, event: fidl_mlme::MlmeEvent);
166 fn on_timeout(&mut self, timed_event: timer::Event<Self::Event>);
167}
168
169pub type MlmeStream = mpsc::UnboundedReceiver<MlmeRequest>;
170pub type MlmeEventStream = mpsc::UnboundedReceiver<MlmeEvent>;
171pub type MlmeSink = UnboundedSink<MlmeRequest>;
172pub type MlmeEventSink = UnboundedSink<MlmeEvent>;
173
174pub mod responder {
175 use futures::channel::oneshot;
176
177 #[derive(Debug)]
178 pub struct Responder<T>(oneshot::Sender<T>);
179
180 impl<T> Responder<T> {
181 pub fn new() -> (Self, oneshot::Receiver<T>) {
182 let (sender, receiver) = oneshot::channel();
183 (Responder(sender), receiver)
184 }
185
186 pub fn respond(self, result: T) {
187 #[allow(
188 clippy::unnecessary_lazy_evaluations,
189 reason = "mass allow for https://fxbug.dev/381896734"
190 )]
191 self.0.send(result).unwrap_or_else(|_| ());
192 }
193 }
194}
195
196fn mlme_event_name(event: &MlmeEvent) -> &str {
198 match event {
199 MlmeEvent::OnScanResult { .. } => "OnScanResult",
200 MlmeEvent::OnScanEnd { .. } => "OnScanEnd",
201 MlmeEvent::ConnectConf { .. } => "ConnectConf",
202 MlmeEvent::RoamConf { .. } => "RoamConf",
203 MlmeEvent::RoamStartInd { .. } => "RoamStartInd",
204 MlmeEvent::RoamResultInd { .. } => "RoamResultInd",
205 MlmeEvent::AuthenticateInd { .. } => "AuthenticateInd",
206 MlmeEvent::DeauthenticateConf { .. } => "DeauthenticateConf",
207 MlmeEvent::DeauthenticateInd { .. } => "DeauthenticateInd",
208 MlmeEvent::AssociateInd { .. } => "AssociateInd",
209 MlmeEvent::DisassociateConf { .. } => "DisassociateConf",
210 MlmeEvent::DisassociateInd { .. } => "DisassociateInd",
211 MlmeEvent::SetKeysConf { .. } => "SetKeysConf",
212 MlmeEvent::StartConf { .. } => "StartConf",
213 MlmeEvent::StopConf { .. } => "StopConf",
214 MlmeEvent::EapolConf { .. } => "EapolConf",
215 MlmeEvent::SignalReport { .. } => "SignalReport",
216 MlmeEvent::OnRssiThresholdBreached { .. } => "OnRssiThresholdBreached",
217 MlmeEvent::EapolInd { .. } => "EapolInd",
218 MlmeEvent::RelayCapturedFrame { .. } => "RelayCapturedFrame",
219 MlmeEvent::OnChannelSwitched { .. } => "OnChannelSwitched",
220 MlmeEvent::OnPmkAvailable { .. } => "OnPmkAvailable",
221 MlmeEvent::OnSaeHandshakeInd { .. } => "OnSaeHandshakeInd",
222 MlmeEvent::OnSaeFrameRx { .. } => "OnSaeFrameRx",
223 MlmeEvent::OnWmmStatusResp { .. } => "OnWmmStatusResp",
224 MlmeEvent::OnScheduledScanMatchesAvailable { .. } => "OnScheduledScanMatchesAvailable",
225 MlmeEvent::OnScheduledScanStoppedByFirmware { .. } => "OnScheduledScanStoppedByFirmware",
226 }
227}
228
229#[derive(Debug, Error)]
230pub enum Error {
231 #[error("scan end while not scanning")]
232 ScanEndNotScanning,
233 #[error("scan end with wrong txn id")]
234 ScanEndWrongTxnId,
235 #[error("scan result while not scanning")]
236 ScanResultNotScanning,
237 #[error("scan result with wrong txn id")]
238 ScanResultWrongTxnId,
239}