wlan_hw_sim/
netdevice_helper.rs1use fidl::endpoints::{Proxy, create_proxy};
6use fuchsia_component::client::connect_to_named_protocol_at_dir_root;
7use futures::{FutureExt as _, StreamExt as _, TryStreamExt as _};
8use std::pin::pin;
9use wlan_common::append::Append;
10use wlan_common::mac;
11use zerocopy::byteorder::big_endian::U16 as BigEndianU16;
12
13pub async fn create_client(
15 devfs: &fidl_fuchsia_io::DirectoryProxy,
16 mac: fidl_fuchsia_net::MacAddress,
17) -> Option<(netdevice_client::Client, netdevice_client::Port)> {
18 let (directory, directory_server) = create_proxy::<fidl_fuchsia_io::DirectoryMarker>();
19
20 fdio::open_at(
21 devfs.as_channel().as_ref(),
22 "class/network",
23 fidl_fuchsia_io::PERM_READABLE,
24 directory_server.into_channel(),
25 )
26 .expect("connect to /dev/class/network");
27
28 let dirents = fuchsia_fs::directory::readdir(&directory).await.expect("readdir failed");
29 let devices = dirents.into_iter().map(|file| {
30 log::info!("Found file name {:?}", file.name);
31 connect_to_named_protocol_at_dir_root::<fidl_fuchsia_hardware_network::DeviceMarker>(
32 &directory, &file.name,
33 )
34 .expect("creating proxy")
35 });
36
37 let results = futures::stream::iter(devices).filter_map(|device_proxy| async move {
40 let client = netdevice_client::Client::new(device_proxy);
41
42 let port_id = match client
43 .device_port_event_stream()
44 .expect("failed to get port event stream")
45 .try_next()
46 .await
47 .expect("error observing ports")
48 .expect("port stream ended unexpectedly")
49 {
50 fidl_fuchsia_hardware_network::DevicePortEvent::Existing(port_id) => port_id,
51 e @ fidl_fuchsia_hardware_network::DevicePortEvent::Removed(_)
52 | e @ fidl_fuchsia_hardware_network::DevicePortEvent::Idle(_)
53 | e @ fidl_fuchsia_hardware_network::DevicePortEvent::Added(_) => {
54 unreachable!("unexpected event: {:?}", e);
55 }
56 };
57 let netdev_port = port_id.try_into().expect("bad port id");
58 let port_proxy = client.connect_port(netdev_port).expect("failed to connect port");
59 let (mac_addressing, mac_addressing_server) =
60 fidl::endpoints::create_proxy::<fidl_fuchsia_hardware_network::MacAddressingMarker>();
61 port_proxy.get_mac(mac_addressing_server).expect("failed to get mac addressing");
62 let addr = mac_addressing.get_unicast_address().await.expect("failed to get address");
63
64 (addr.octets == mac.octets).then(move || (client, netdev_port))
65 });
66 let mut results = pin!(results);
67 results.next().await
68}
69
70pub async fn start_session(
73 client: netdevice_client::Client,
74 port: netdevice_client::Port,
75) -> (netdevice_client::Session, fuchsia_async::Task<()>) {
76 let info = client.device_info().await.expect("get device info");
77 let (session, task) = client
78 .new_session_with_derivable_config(
79 "wlan-test",
80 netdevice_client::DerivableConfig {
81 default_buffer_length: info
82 .base_info
83 .max_buffer_length
84 .expect("buffer length not set in DeviceInfo")
85 .get() as usize,
86 ..Default::default()
87 },
88 )
89 .await
90 .expect("open primary session");
91 let task_handle = fuchsia_async::Task::spawn(task.map(|r| r.expect("session task failed")));
92 session
93 .attach(port, &[fidl_fuchsia_hardware_network::FrameType::Ethernet])
94 .await
95 .expect("attach port");
96
97 let (watcher_proxy, watcher_server) = fidl::endpoints::create_proxy();
98 client
99 .connect_port(port)
100 .expect("Failed to connect to port")
101 .get_status_watcher(watcher_server, fidl_fuchsia_hardware_network::MAX_STATUS_BUFFER)
104 .unwrap();
105
106 loop {
109 if let Some(flags) = watcher_proxy.watch_status().await.unwrap().flags {
110 if flags == fidl_fuchsia_hardware_network::StatusFlags::ONLINE {
111 log::info!("Network device port online!");
112 break;
113 }
114 log::info!("Waiting for network device port to come online...");
115 }
116 }
117
118 (session, task_handle)
119}
120
121pub async fn send(session: &netdevice_client::Session, port: &netdevice_client::Port, data: &[u8]) {
122 let mut buffer = session.alloc_tx_buffer(data.len()).await.expect("allocate tx buffer");
123 buffer.set_frame_type(fidl_fuchsia_hardware_network::FrameType::Ethernet);
124 buffer.set_port(*port);
125 buffer.write_at(0, &data).expect("write message");
126 session.send(buffer).expect("failed to send data");
127}
128
129pub async fn recv(session: &netdevice_client::Session) -> Vec<u8> {
130 let recv_result = session.recv().await.expect("recv failed");
131 let mut buffer = vec![0; recv_result.len()];
132 recv_result.read_at(0, &mut buffer).expect("read from buffer");
133 buffer
134}
135
136pub fn write_fake_frame(da: ieee80211::MacAddr, sa: ieee80211::MacAddr, payload: &[u8]) -> Vec<u8> {
137 let mut buf = vec![];
138 buf.append_value(&mac::EthernetIIHdr {
139 da,
140 sa,
141 ether_type: BigEndianU16::new(mac::ETHER_TYPE_IPV4),
142 })
143 .expect("error creating fake ethernet header");
144 buf.append_bytes(payload).expect("buffer too small for ethernet payload");
145 buf
146}