1use anyhow::{Context as _, Error, format_err};
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.query_iface(iface_id).await.context("Error querying iface")?.map_err(|e| {
95 format_err!("query_iface {} failed: {}", iface_id, zx::Status::err_from_raw(e))
96 })
97}
98
99pub async fn get_wlan_sta_addr(
100 monitor_proxy: &DeviceMonitorProxy,
101 iface_id: u16,
102) -> Result<[u8; 6], Error> {
103 let iface_info = query_iface(monitor_proxy, iface_id).await?;
104 Ok(iface_info.sta_addr)
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110 use assert_matches::assert_matches;
111 use fidl_fuchsia_wlan_common::WlanMacRole;
112 use fidl_fuchsia_wlan_device_service::{
113 DeviceMonitorCreateIfaceResponse, DeviceMonitorMarker, DeviceMonitorRequest,
114 DeviceMonitorRequestStream,
115 };
116 use fuchsia_async::TestExecutor;
117 use futures::StreamExt;
118 use futures::task::Poll;
119 use std::pin::pin;
120
121 pub(crate) fn setup_fake_service<M: fidl::endpoints::ProtocolMarker>()
122 -> (fuchsia_async::TestExecutor, M::Proxy, M::RequestStream) {
123 let exec = fuchsia_async::TestExecutor::new();
124 let (proxy, server) = fidl::endpoints::create_proxy::<M>();
125 (exec, proxy, server.into_stream())
126 }
127
128 fn fake_iface_query_response(
129 sta_addr: [u8; 6],
130 role: fidl_fuchsia_wlan_common::WlanMacRole,
131 ) -> QueryIfaceResponse {
132 QueryIfaceResponse {
133 role,
134 id: 0,
135 phy_id: 0,
136 phy_assigned_id: 0,
137 sta_addr,
138 factory_addr: sta_addr,
139 }
140 }
141
142 pub fn respond_to_query_iface_list_request(
143 exec: &mut TestExecutor,
144 req_stream: &mut DeviceMonitorRequestStream,
145 ifaces: Vec<u16>,
146 ) {
147 let req = exec.run_until_stalled(&mut req_stream.next());
148 let responder = assert_matches!(
149 req,
150 Poll::Ready(Some(Ok(DeviceMonitorRequest::ListIfaces { responder }))) => responder
151 );
152 responder.send(&ifaces[..]).expect("fake query iface list response: send failed")
153 }
154
155 pub fn respond_to_query_iface_request(
156 exec: &mut TestExecutor,
157 req_stream: &mut DeviceMonitorRequestStream,
158 role: fidl_fuchsia_wlan_common::WlanMacRole,
159 fake_mac_addr: Option<[u8; 6]>,
160 ) {
161 let req = exec.run_until_stalled(&mut req_stream.next());
162 let responder = assert_matches!(
163 req,
164 Poll::Ready(Some(Ok(DeviceMonitorRequest::QueryIface { iface_id: _, responder }))) => responder
165 );
166 if let Some(mac) = fake_mac_addr {
167 let response = fake_iface_query_response(mac, role);
168 responder.send(Ok(&response)).expect("sending fake response with mac address");
169 } else {
170 responder.send(Err(zx::sys::ZX_ERR_NOT_FOUND)).expect("sending fake response with none")
171 }
172 }
173
174 pub fn respond_to_create_iface_request(
175 exec: &mut TestExecutor,
176 req_stream: &mut DeviceMonitorRequestStream,
177 fake_response: Result<u16, i32>,
178 ) {
179 let req = exec.run_until_stalled(&mut req_stream.next());
180 let responder = assert_matches!(
181 req,
182 Poll::Ready(Some(Ok(DeviceMonitorRequest::CreateIface { responder, .. }))) => responder
183 );
184
185 let fake_response = fake_response
186 .map(|fake_iface_id| DeviceMonitorCreateIfaceResponse {
187 iface_id: Some(fake_iface_id),
188 ..Default::default()
189 })
190 .map_err(|_| fidl_fuchsia_wlan_device_service::DeviceMonitorError::Internal);
191 responder
192 .send(fake_response.as_ref().map_err(|e| *e))
193 .expect("sending fake response with iface id");
194 }
195
196 #[test]
197 fn test_get_wlan_sta_addr_ok() {
198 let (mut exec, proxy, mut req_stream) = setup_fake_service::<DeviceMonitorMarker>();
199 let mac_addr_fut = get_wlan_sta_addr(&proxy, 0);
200 let mut mac_addr_fut = pin!(mac_addr_fut);
201
202 assert_matches!(exec.run_until_stalled(&mut mac_addr_fut), Poll::Pending);
203
204 respond_to_query_iface_request(
205 &mut exec,
206 &mut req_stream,
207 WlanMacRole::Client,
208 Some([1, 2, 3, 4, 5, 6]),
209 );
210
211 let mac_addr = exec.run_singlethreaded(&mut mac_addr_fut).expect("should get a mac addr");
212 assert_eq!(mac_addr, [1, 2, 3, 4, 5, 6]);
213 }
214
215 #[test]
216 fn test_get_wlan_sta_addr_not_found() {
217 let (mut exec, proxy, mut req_stream) = setup_fake_service::<DeviceMonitorMarker>();
218 let mac_addr_fut = get_wlan_sta_addr(&proxy, 0);
219 let mut mac_addr_fut = pin!(mac_addr_fut);
220
221 assert_matches!(exec.run_until_stalled(&mut mac_addr_fut), Poll::Pending);
222
223 respond_to_query_iface_request(&mut exec, &mut req_stream, WlanMacRole::Client, None);
224
225 let err = exec.run_singlethreaded(&mut mac_addr_fut).expect_err("should be an error");
226 assert!(format!("{}", err).contains("NOT_FOUND"));
227 }
228
229 #[test]
230 fn test_get_wlan_sta_addr_service_interrupted() {
231 let (mut exec, proxy, req_stream) = setup_fake_service::<DeviceMonitorMarker>();
232 let mac_addr_fut = get_wlan_sta_addr(&proxy, 0);
233 let mut mac_addr_fut = pin!(mac_addr_fut);
234
235 assert_matches!(exec.run_until_stalled(&mut mac_addr_fut), Poll::Pending);
236
237 std::mem::drop(req_stream);
239
240 let err = exec.run_singlethreaded(&mut mac_addr_fut).expect_err("should be an error");
241 assert!(format!("{}", err).contains("Error querying iface"));
242 }
243
244 #[test]
245 fn test_create_iface_ok() {
246 let (mut exec, proxy, mut req_stream) = setup_fake_service::<DeviceMonitorMarker>();
247 let iface_id_fut = create_iface(&proxy, 0, WlanMacRole::Client, [0, 0, 0, 0, 0, 0].into());
248
249 let mut iface_id_fut = pin!(iface_id_fut);
250
251 assert_matches!(exec.run_until_stalled(&mut iface_id_fut), Poll::Pending);
252 respond_to_create_iface_request(&mut exec, &mut req_stream, Ok(15));
253
254 let iface_id = exec.run_singlethreaded(&mut iface_id_fut).expect("should get an iface id");
255
256 assert_eq!(iface_id, 15);
257 }
258
259 #[test]
260 fn test_create_iface_internal_err() {
261 let (mut exec, proxy, mut req_stream) = setup_fake_service::<DeviceMonitorMarker>();
262 let iface_id_fut = create_iface(&proxy, 0, WlanMacRole::Client, [0, 0, 0, 0, 0, 0].into());
263
264 let mut iface_id_fut = pin!(iface_id_fut);
265
266 assert_matches!(exec.run_until_stalled(&mut iface_id_fut), Poll::Pending);
267 respond_to_create_iface_request(&mut exec, &mut req_stream, Err(zx::sys::ZX_ERR_INTERNAL));
268
269 let err = exec.run_singlethreaded(&mut iface_id_fut).expect_err("Should get an error");
270 assert!(format!("{}", err).contains("Internal"));
271 }
272}