1use anyhow::{format_err, Context as _, Error};
6use fidl_fuchsia_wlan_common::WlanMacRole;
7use fidl_fuchsia_wlan_device_service::{
8 DestroyIfaceRequest, DeviceMonitorCreateIfaceRequest, DeviceMonitorCreateIfaceResponse,
9 DeviceMonitorProxy, QueryIfaceResponse,
10};
11use log::info;
12
13use ieee80211::{MacAddr, MacAddrBytes};
14
15pub mod ap;
16pub mod client;
17
18pub async fn get_iface_list(monitor_proxy: &DeviceMonitorProxy) -> Result<Vec<u16>, Error> {
20 monitor_proxy.list_ifaces().await.context("Error getting iface list")
21}
22
23pub async fn get_first_iface(
29 monitor_proxy: &DeviceMonitorProxy,
30 role: WlanMacRole,
31) -> Result<u16, Error> {
32 let wlan_iface_ids =
33 get_iface_list(monitor_proxy).await.context("Connect: failed to get wlan iface list")?;
34
35 if wlan_iface_ids.len() == 0 {
36 return Err(format_err!("No wlan interface found"));
37 }
38 info!("Found {} wlan iface entries", wlan_iface_ids.len());
39 for iface_id in wlan_iface_ids {
40 let iface_info = query_iface(monitor_proxy, iface_id).await?;
41
42 if iface_info.role == role {
43 return Ok(iface_id);
44 }
45 }
46 Err(format_err!("interface with role {:?} not found", role))
47}
48pub async fn get_phy_list(monitor_proxy: &DeviceMonitorProxy) -> Result<Vec<u16>, Error> {
53 let phys = monitor_proxy.list_phys().await.context("Error getting phy list")?;
54 Ok(phys)
55}
56
57pub async fn create_iface(
58 monitor_proxy: &DeviceMonitorProxy,
59 phy_id: u16,
60 role: WlanMacRole,
61 sta_address: MacAddr,
62) -> Result<u16, Error> {
63 let req = DeviceMonitorCreateIfaceRequest {
64 phy_id: Some(phy_id),
65 role: Some(role),
66 sta_address: Some(sta_address.to_array()),
67 ..Default::default()
68 };
69
70 match monitor_proxy.create_iface(&req).await.context("FIDL error creating iface")? {
71 Err(e) => Err(format_err!("Error creating iface: {:?}", e)),
72 Ok(DeviceMonitorCreateIfaceResponse { iface_id: None, .. }) => {
73 Err(format_err!("Create iface completed without returning an iface id"))
74 }
75 Ok(DeviceMonitorCreateIfaceResponse { iface_id: Some(iface_id), .. }) => {
76 info!("Created iface {:?}", iface_id);
77 Ok(iface_id)
78 }
79 }
80}
81
82pub async fn destroy_iface(monitor_proxy: &DeviceMonitorProxy, iface_id: u16) -> Result<(), Error> {
83 let req = DestroyIfaceRequest { iface_id };
84
85 let response = monitor_proxy.destroy_iface(&req).await.context("Error destroying iface")?;
86 zx::Status::ok(response).context("Destroy iface returned non-OK status")?;
87 Ok(info!("Destroyed iface {:?}", iface_id))
88}
89
90async fn query_iface(
91 monitor_proxy: &DeviceMonitorProxy,
92 iface_id: u16,
93) -> Result<QueryIfaceResponse, Error> {
94 monitor_proxy
95 .query_iface(iface_id)
96 .await
97 .context("Error querying iface")?
98 .map_err(|e| format_err!("query_iface {} failed: {}", iface_id, zx::Status::from_raw(e)))
99}
100
101pub async fn get_wlan_sta_addr(
102 monitor_proxy: &DeviceMonitorProxy,
103 iface_id: u16,
104) -> Result<[u8; 6], Error> {
105 let iface_info = query_iface(monitor_proxy, iface_id).await?;
106 Ok(iface_info.sta_addr)
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112 use fidl_fuchsia_wlan_common::WlanMacRole;
113 use fidl_fuchsia_wlan_device_service::{
114 DeviceMonitorCreateIfaceResponse, DeviceMonitorMarker, DeviceMonitorRequest,
115 DeviceMonitorRequestStream,
116 };
117 use fuchsia_async::TestExecutor;
118 use futures::task::Poll;
119 use futures::StreamExt;
120 use std::pin::pin;
121 use wlan_common::assert_variant;
122
123 pub(crate) fn setup_fake_service<M: fidl::endpoints::ProtocolMarker>(
124 ) -> (fuchsia_async::TestExecutor, M::Proxy, M::RequestStream) {
125 let exec = fuchsia_async::TestExecutor::new();
126 let (proxy, server) = fidl::endpoints::create_proxy::<M>();
127 (exec, proxy, server.into_stream())
128 }
129
130 fn fake_iface_query_response(
131 sta_addr: [u8; 6],
132 role: fidl_fuchsia_wlan_common::WlanMacRole,
133 ) -> QueryIfaceResponse {
134 QueryIfaceResponse { role, id: 0, phy_id: 0, phy_assigned_id: 0, sta_addr }
135 }
136
137 pub fn respond_to_query_iface_list_request(
138 exec: &mut TestExecutor,
139 req_stream: &mut DeviceMonitorRequestStream,
140 ifaces: Vec<u16>,
141 ) {
142 let req = exec.run_until_stalled(&mut req_stream.next());
143 let responder = assert_variant !(
144 req,
145 Poll::Ready(Some(Ok(DeviceMonitorRequest::ListIfaces{responder})))
146 => responder);
147 responder.send(&ifaces[..]).expect("fake query iface list response: send failed")
148 }
149
150 pub fn respond_to_query_iface_request(
151 exec: &mut TestExecutor,
152 req_stream: &mut DeviceMonitorRequestStream,
153 role: fidl_fuchsia_wlan_common::WlanMacRole,
154 fake_mac_addr: Option<[u8; 6]>,
155 ) {
156 let req = exec.run_until_stalled(&mut req_stream.next());
157 let responder = assert_variant !(
158 req,
159 Poll::Ready(Some(Ok(DeviceMonitorRequest::QueryIface{iface_id : _, responder})))
160 => responder);
161 if let Some(mac) = fake_mac_addr {
162 let response = fake_iface_query_response(mac, role);
163 responder.send(Ok(&response)).expect("sending fake response with mac address");
164 } else {
165 responder.send(Err(zx::sys::ZX_ERR_NOT_FOUND)).expect("sending fake response with none")
166 }
167 }
168
169 pub fn respond_to_create_iface_request(
170 exec: &mut TestExecutor,
171 req_stream: &mut DeviceMonitorRequestStream,
172 fake_response: Result<u16, i32>,
173 ) {
174 let req = exec.run_until_stalled(&mut req_stream.next());
175 let responder = assert_variant !(
176 req,
177 Poll::Ready(Some(Ok(DeviceMonitorRequest::CreateIface{responder, ..})))
178 => responder);
179
180 let fake_response = fake_response.map_ok(|fake_iface_id| {
181 DeviceMonitorCreateIfaceResponse { iface_id: Some(fake_iface_id), ..Default::default() }
182 });
183 responder.send(fake_response).expect("sending fake response with iface id");
184 }
185
186 #[test]
187 fn test_get_wlan_sta_addr_ok() {
188 let (mut exec, proxy, mut req_stream) = setup_fake_service::<DeviceMonitorMarker>();
189 let mac_addr_fut = get_wlan_sta_addr(&proxy, 0);
190 let mut mac_addr_fut = pin!(mac_addr_fut);
191
192 assert_variant!(exec.run_until_stalled(&mut mac_addr_fut), Poll::Pending);
193
194 respond_to_query_iface_request(
195 &mut exec,
196 &mut req_stream,
197 WlanMacRole::Client,
198 Some([1, 2, 3, 4, 5, 6]),
199 );
200
201 let mac_addr = exec.run_singlethreaded(&mut mac_addr_fut).expect("should get a mac addr");
202 assert_eq!(mac_addr, [1, 2, 3, 4, 5, 6]);
203 }
204
205 #[test]
206 fn test_get_wlan_sta_addr_not_found() {
207 let (mut exec, proxy, mut req_stream) = setup_fake_service::<DeviceMonitorMarker>();
208 let mac_addr_fut = get_wlan_sta_addr(&proxy, 0);
209 let mut mac_addr_fut = pin!(mac_addr_fut);
210
211 assert_variant!(exec.run_until_stalled(&mut mac_addr_fut), Poll::Pending);
212
213 respond_to_query_iface_request(&mut exec, &mut req_stream, WlanMacRole::Client, None);
214
215 let err = exec.run_singlethreaded(&mut mac_addr_fut).expect_err("should be an error");
216 assert!(format!("{}", err).contains("NOT_FOUND"));
217 }
218
219 #[test]
220 fn test_get_wlan_sta_addr_service_interrupted() {
221 let (mut exec, proxy, req_stream) = setup_fake_service::<DeviceMonitorMarker>();
222 let mac_addr_fut = get_wlan_sta_addr(&proxy, 0);
223 let mut mac_addr_fut = pin!(mac_addr_fut);
224
225 assert_variant!(exec.run_until_stalled(&mut mac_addr_fut), Poll::Pending);
226
227 std::mem::drop(req_stream);
229
230 let err = exec.run_singlethreaded(&mut mac_addr_fut).expect_err("should be an error");
231 assert!(format!("{}", err).contains("Error querying iface"));
232 }
233
234 #[test]
235 fn test_create_iface_ok() {
236 let (mut exec, proxy, mut req_stream) = setup_fake_service::<DeviceMonitorMarker>();
237 let iface_id_fut = create_iface(&proxy, 0, WlanMacRole::Client, [0, 0, 0, 0, 0, 0].into());
238
239 let mut iface_id_fut = pin!(iface_id_fut);
240
241 assert_variant!(exec.run_until_stalled(&mut iface_id_fut), Poll::Pending);
242 respond_to_create_iface_request(&mut exec, &mut req_stream, Ok(15));
243
244 let iface_id = exec.run_singlethreaded(&mut iface_id_fut).expect("should get an iface id");
245
246 assert_eq!(iface_id, 15);
247 }
248
249 #[test]
250 fn test_create_iface_internal_err() {
251 let (mut exec, proxy, mut req_stream) = setup_fake_service::<DeviceMonitorMarker>();
252 let iface_id_fut = create_iface(&proxy, 0, WlanMacRole::Client, [0, 0, 0, 0, 0, 0].into());
253
254 let mut iface_id_fut = pin!(iface_id_fut);
255
256 assert_variant!(exec.run_until_stalled(&mut iface_id_fut), Poll::Pending);
257 respond_to_create_iface_request(&mut exec, &mut req_stream, Err(zx::sys::ZX_ERR_INTERNAL));
258
259 let err = exec.run_singlethreaded(&mut iface_id_fut).expect_err("Should get an error");
260 assert!(format!("{}", err).contains("INTERNAL"));
261 }
262}