xref: /aosp_15_r20/tools/netsim/rust/hostapd-rs/src/hostapd.rs (revision cf78ab8cffb8fc9207af348f23af247fb04370a6)
1*cf78ab8cSAndroid Build Coastguard Worker // Copyright 2024 Google LLC
2*cf78ab8cSAndroid Build Coastguard Worker //
3*cf78ab8cSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*cf78ab8cSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*cf78ab8cSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*cf78ab8cSAndroid Build Coastguard Worker //
7*cf78ab8cSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*cf78ab8cSAndroid Build Coastguard Worker //
9*cf78ab8cSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*cf78ab8cSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*cf78ab8cSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*cf78ab8cSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*cf78ab8cSAndroid Build Coastguard Worker // limitations under the License.
14*cf78ab8cSAndroid Build Coastguard Worker 
15*cf78ab8cSAndroid Build Coastguard Worker //! Controller interface for the `hostapd` C library.
16*cf78ab8cSAndroid Build Coastguard Worker //!
17*cf78ab8cSAndroid Build Coastguard Worker //! This module allows interaction with `hostapd` to manage WiFi access point and perform various wireless networking tasks directly from Rust code.
18*cf78ab8cSAndroid Build Coastguard Worker //!
19*cf78ab8cSAndroid Build Coastguard Worker //! The main `hostapd` process is managed by a separate thread while responses from the `hostapd` process are handled
20*cf78ab8cSAndroid Build Coastguard Worker //! by another thread, ensuring efficient and non-blocking communication.
21*cf78ab8cSAndroid Build Coastguard Worker //!
22*cf78ab8cSAndroid Build Coastguard Worker //! `hostapd` configuration consists of key-value pairs. The default configuration file is generated in the discovery directory.
23*cf78ab8cSAndroid Build Coastguard Worker //!
24*cf78ab8cSAndroid Build Coastguard Worker //! ## Features
25*cf78ab8cSAndroid Build Coastguard Worker //!
26*cf78ab8cSAndroid Build Coastguard Worker //! * **Asynchronous operation:** The module utilizes `tokio` for asynchronous communication with the `hostapd` process,
27*cf78ab8cSAndroid Build Coastguard Worker //!   allowing for efficient and non-blocking operations.
28*cf78ab8cSAndroid Build Coastguard Worker //! * **Platform support:** Supports Linux, macOS, and Windows.
29*cf78ab8cSAndroid Build Coastguard Worker //! * **Configuration management:** Provides functionality to generate and manage `hostapd` configuration files.
30*cf78ab8cSAndroid Build Coastguard Worker //! * **Easy integration:** Offers a high-level API to simplify interaction with `hostapd`, abstracting away
31*cf78ab8cSAndroid Build Coastguard Worker //!   low-level details.
32*cf78ab8cSAndroid Build Coastguard Worker //!
33*cf78ab8cSAndroid Build Coastguard Worker //! ## Usage
34*cf78ab8cSAndroid Build Coastguard Worker //!
35*cf78ab8cSAndroid Build Coastguard Worker //! Here's a basic example of how to create a `Hostapd` instance and start the `hostapd` process:
36*cf78ab8cSAndroid Build Coastguard Worker //!
37*cf78ab8cSAndroid Build Coastguard Worker //! ```
38*cf78ab8cSAndroid Build Coastguard Worker //! use hostapd_rs::hostapd::Hostapd;
39*cf78ab8cSAndroid Build Coastguard Worker //! use std::path::PathBuf;
40*cf78ab8cSAndroid Build Coastguard Worker //! use std::sync::mpsc;
41*cf78ab8cSAndroid Build Coastguard Worker //!
42*cf78ab8cSAndroid Build Coastguard Worker //! fn main() {
43*cf78ab8cSAndroid Build Coastguard Worker //!     // Create a channel for receiving data from hostapd
44*cf78ab8cSAndroid Build Coastguard Worker //!     let (tx, _) = mpsc::channel();
45*cf78ab8cSAndroid Build Coastguard Worker //!
46*cf78ab8cSAndroid Build Coastguard Worker //!     // Create a new Hostapd instance
47*cf78ab8cSAndroid Build Coastguard Worker //!     let mut hostapd = Hostapd::new(
48*cf78ab8cSAndroid Build Coastguard Worker //!         tx,                                 // Sender for receiving data
49*cf78ab8cSAndroid Build Coastguard Worker //!         true,                               // Verbose mode (optional)
50*cf78ab8cSAndroid Build Coastguard Worker //!         PathBuf::from("/tmp/hostapd.conf"), // Path to the configuration file
51*cf78ab8cSAndroid Build Coastguard Worker //!     );
52*cf78ab8cSAndroid Build Coastguard Worker //!
53*cf78ab8cSAndroid Build Coastguard Worker //!     // Start the hostapd process
54*cf78ab8cSAndroid Build Coastguard Worker //!     hostapd.run();
55*cf78ab8cSAndroid Build Coastguard Worker //! }
56*cf78ab8cSAndroid Build Coastguard Worker //! ```
57*cf78ab8cSAndroid Build Coastguard Worker //!
58*cf78ab8cSAndroid Build Coastguard Worker //! This starts `hostapd` in a separate thread, allowing interaction with it using the `Hostapd` struct's methods.
59*cf78ab8cSAndroid Build Coastguard Worker 
60*cf78ab8cSAndroid Build Coastguard Worker use anyhow::bail;
61*cf78ab8cSAndroid Build Coastguard Worker use bytes::Bytes;
62*cf78ab8cSAndroid Build Coastguard Worker use log::{info, warn};
63*cf78ab8cSAndroid Build Coastguard Worker use netsim_packets::ieee80211::{Ieee80211, MacAddress};
64*cf78ab8cSAndroid Build Coastguard Worker use std::collections::HashMap;
65*cf78ab8cSAndroid Build Coastguard Worker use std::ffi::{c_char, c_int, CStr, CString};
66*cf78ab8cSAndroid Build Coastguard Worker use std::fs::File;
67*cf78ab8cSAndroid Build Coastguard Worker use std::io::{BufWriter, Write};
68*cf78ab8cSAndroid Build Coastguard Worker use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
69*cf78ab8cSAndroid Build Coastguard Worker #[cfg(unix)]
70*cf78ab8cSAndroid Build Coastguard Worker use std::os::fd::IntoRawFd;
71*cf78ab8cSAndroid Build Coastguard Worker #[cfg(windows)]
72*cf78ab8cSAndroid Build Coastguard Worker use std::os::windows::io::IntoRawSocket;
73*cf78ab8cSAndroid Build Coastguard Worker use std::path::PathBuf;
74*cf78ab8cSAndroid Build Coastguard Worker use std::sync::{mpsc, Arc, RwLock};
75*cf78ab8cSAndroid Build Coastguard Worker use std::thread::{self, sleep};
76*cf78ab8cSAndroid Build Coastguard Worker use std::time::Duration;
77*cf78ab8cSAndroid Build Coastguard Worker use tokio::io::{AsyncReadExt, AsyncWriteExt};
78*cf78ab8cSAndroid Build Coastguard Worker use tokio::net::{
79*cf78ab8cSAndroid Build Coastguard Worker     tcp::{OwnedReadHalf, OwnedWriteHalf},
80*cf78ab8cSAndroid Build Coastguard Worker     TcpListener, TcpStream,
81*cf78ab8cSAndroid Build Coastguard Worker };
82*cf78ab8cSAndroid Build Coastguard Worker use tokio::runtime::Runtime;
83*cf78ab8cSAndroid Build Coastguard Worker use tokio::sync::Mutex;
84*cf78ab8cSAndroid Build Coastguard Worker 
85*cf78ab8cSAndroid Build Coastguard Worker use crate::hostapd_sys::{
86*cf78ab8cSAndroid Build Coastguard Worker     run_hostapd_main, set_virtio_ctrl_sock, set_virtio_sock, VIRTIO_WIFI_CTRL_CMD_RELOAD_CONFIG,
87*cf78ab8cSAndroid Build Coastguard Worker     VIRTIO_WIFI_CTRL_CMD_TERMINATE,
88*cf78ab8cSAndroid Build Coastguard Worker };
89*cf78ab8cSAndroid Build Coastguard Worker 
90*cf78ab8cSAndroid Build Coastguard Worker /// Alias for RawFd on Unix or RawSocket on Windows (converted to i32)
91*cf78ab8cSAndroid Build Coastguard Worker type RawDescriptor = i32;
92*cf78ab8cSAndroid Build Coastguard Worker 
93*cf78ab8cSAndroid Build Coastguard Worker /// Hostapd process interface.
94*cf78ab8cSAndroid Build Coastguard Worker ///
95*cf78ab8cSAndroid Build Coastguard Worker /// This struct provides methods for interacting with the `hostapd` process,
96*cf78ab8cSAndroid Build Coastguard Worker /// such as starting and stopping the process, configuring the access point,
97*cf78ab8cSAndroid Build Coastguard Worker /// and sending and receiving data.
98*cf78ab8cSAndroid Build Coastguard Worker pub struct Hostapd {
99*cf78ab8cSAndroid Build Coastguard Worker     // TODO: update to tokio based RwLock when usages are async
100*cf78ab8cSAndroid Build Coastguard Worker     handle: RwLock<Option<thread::JoinHandle<()>>>,
101*cf78ab8cSAndroid Build Coastguard Worker     verbose: bool,
102*cf78ab8cSAndroid Build Coastguard Worker     config: HashMap<String, String>,
103*cf78ab8cSAndroid Build Coastguard Worker     config_path: PathBuf,
104*cf78ab8cSAndroid Build Coastguard Worker     data_writer: Option<Mutex<OwnedWriteHalf>>,
105*cf78ab8cSAndroid Build Coastguard Worker     ctrl_writer: Option<Mutex<OwnedWriteHalf>>,
106*cf78ab8cSAndroid Build Coastguard Worker     tx_bytes: mpsc::Sender<Bytes>,
107*cf78ab8cSAndroid Build Coastguard Worker     runtime: Arc<Runtime>,
108*cf78ab8cSAndroid Build Coastguard Worker     // MAC address of the access point.
109*cf78ab8cSAndroid Build Coastguard Worker     bssid: MacAddress,
110*cf78ab8cSAndroid Build Coastguard Worker }
111*cf78ab8cSAndroid Build Coastguard Worker 
112*cf78ab8cSAndroid Build Coastguard Worker impl Hostapd {
113*cf78ab8cSAndroid Build Coastguard Worker     /// Creates a new `Hostapd` instance.
114*cf78ab8cSAndroid Build Coastguard Worker     ///
115*cf78ab8cSAndroid Build Coastguard Worker     /// # Arguments
116*cf78ab8cSAndroid Build Coastguard Worker     ///
117*cf78ab8cSAndroid Build Coastguard Worker     /// * `tx_bytes`: Sender for transmitting data received from `hostapd`.
118*cf78ab8cSAndroid Build Coastguard Worker     /// * `verbose`: Whether to run `hostapd` in verbose mode.
119*cf78ab8cSAndroid Build Coastguard Worker     /// * `config_path`: Path to the `hostapd` configuration file.
120*cf78ab8cSAndroid Build Coastguard Worker 
new(tx_bytes: mpsc::Sender<Bytes>, verbose: bool, config_path: PathBuf) -> Self121*cf78ab8cSAndroid Build Coastguard Worker     pub fn new(tx_bytes: mpsc::Sender<Bytes>, verbose: bool, config_path: PathBuf) -> Self {
122*cf78ab8cSAndroid Build Coastguard Worker         // Default Hostapd conf entries
123*cf78ab8cSAndroid Build Coastguard Worker         let config_data = [
124*cf78ab8cSAndroid Build Coastguard Worker             ("ssid", "AndroidWifi"),
125*cf78ab8cSAndroid Build Coastguard Worker             ("interface", "wlan1"),
126*cf78ab8cSAndroid Build Coastguard Worker             ("driver", "virtio_wifi"),
127*cf78ab8cSAndroid Build Coastguard Worker             ("bssid", "00:13:10:95:fe:0b"),
128*cf78ab8cSAndroid Build Coastguard Worker             ("country_code", "US"),
129*cf78ab8cSAndroid Build Coastguard Worker             ("hw_mode", "g"),
130*cf78ab8cSAndroid Build Coastguard Worker             ("channel", "8"),
131*cf78ab8cSAndroid Build Coastguard Worker             ("beacon_int", "1000"),
132*cf78ab8cSAndroid Build Coastguard Worker             ("dtim_period", "2"),
133*cf78ab8cSAndroid Build Coastguard Worker             ("max_num_sta", "255"),
134*cf78ab8cSAndroid Build Coastguard Worker             ("rts_threshold", "2347"),
135*cf78ab8cSAndroid Build Coastguard Worker             ("fragm_threshold", "2346"),
136*cf78ab8cSAndroid Build Coastguard Worker             ("macaddr_acl", "0"),
137*cf78ab8cSAndroid Build Coastguard Worker             ("auth_algs", "3"),
138*cf78ab8cSAndroid Build Coastguard Worker             ("ignore_broadcast_ssid", "0"),
139*cf78ab8cSAndroid Build Coastguard Worker             ("wmm_enabled", "0"),
140*cf78ab8cSAndroid Build Coastguard Worker             ("ieee80211n", "1"),
141*cf78ab8cSAndroid Build Coastguard Worker             ("eapol_key_index_workaround", "0"),
142*cf78ab8cSAndroid Build Coastguard Worker         ];
143*cf78ab8cSAndroid Build Coastguard Worker         let mut config: HashMap<String, String> = HashMap::new();
144*cf78ab8cSAndroid Build Coastguard Worker         config.extend(config_data.iter().map(|(k, v)| (k.to_string(), v.to_string())));
145*cf78ab8cSAndroid Build Coastguard Worker 
146*cf78ab8cSAndroid Build Coastguard Worker         // TODO(b/381154253): Allow configuring BSSID in hostapd.conf.
147*cf78ab8cSAndroid Build Coastguard Worker         // Currently, the BSSID is hardcoded in external/wpa_supplicant_8/src/drivers/driver_virtio_wifi.c. This should be configured by hostapd.conf and allow to be set by `Hostapd`.
148*cf78ab8cSAndroid Build Coastguard Worker         let bssid_bytes: [u8; 6] = [0x00, 0x13, 0x10, 0x85, 0xfe, 0x01];
149*cf78ab8cSAndroid Build Coastguard Worker         let bssid = MacAddress::from(&bssid_bytes);
150*cf78ab8cSAndroid Build Coastguard Worker         Hostapd {
151*cf78ab8cSAndroid Build Coastguard Worker             handle: RwLock::new(None),
152*cf78ab8cSAndroid Build Coastguard Worker             verbose,
153*cf78ab8cSAndroid Build Coastguard Worker             config,
154*cf78ab8cSAndroid Build Coastguard Worker             config_path,
155*cf78ab8cSAndroid Build Coastguard Worker             data_writer: None,
156*cf78ab8cSAndroid Build Coastguard Worker             ctrl_writer: None,
157*cf78ab8cSAndroid Build Coastguard Worker             tx_bytes,
158*cf78ab8cSAndroid Build Coastguard Worker             runtime: Arc::new(Runtime::new().unwrap()),
159*cf78ab8cSAndroid Build Coastguard Worker             bssid,
160*cf78ab8cSAndroid Build Coastguard Worker         }
161*cf78ab8cSAndroid Build Coastguard Worker     }
162*cf78ab8cSAndroid Build Coastguard Worker 
163*cf78ab8cSAndroid Build Coastguard Worker     /// Starts the `hostapd` main process and response thread.
164*cf78ab8cSAndroid Build Coastguard Worker     ///
165*cf78ab8cSAndroid Build Coastguard Worker     /// The "hostapd" thread manages the C `hostapd` process by running `run_hostapd_main`.
166*cf78ab8cSAndroid Build Coastguard Worker     /// The "hostapd_response" thread manages traffic between `hostapd` and netsim.
167*cf78ab8cSAndroid Build Coastguard Worker     ///
168*cf78ab8cSAndroid Build Coastguard Worker     /// TODO:
169*cf78ab8cSAndroid Build Coastguard Worker     /// * update as async fn.
run(&mut self) -> bool170*cf78ab8cSAndroid Build Coastguard Worker     pub fn run(&mut self) -> bool {
171*cf78ab8cSAndroid Build Coastguard Worker         // Check if already running
172*cf78ab8cSAndroid Build Coastguard Worker         assert!(!self.is_running(), "hostapd is already running!");
173*cf78ab8cSAndroid Build Coastguard Worker         // Setup config file
174*cf78ab8cSAndroid Build Coastguard Worker         self.gen_config_file().unwrap_or_else(|_| {
175*cf78ab8cSAndroid Build Coastguard Worker             panic!("Failed to generate config file: {:?}.", self.config_path.display())
176*cf78ab8cSAndroid Build Coastguard Worker         });
177*cf78ab8cSAndroid Build Coastguard Worker 
178*cf78ab8cSAndroid Build Coastguard Worker         // Setup Sockets
179*cf78ab8cSAndroid Build Coastguard Worker         let (ctrl_listener, _ctrl_reader, ctrl_writer) =
180*cf78ab8cSAndroid Build Coastguard Worker             self.create_pipe().expect("Failed to create ctrl pipe");
181*cf78ab8cSAndroid Build Coastguard Worker         self.ctrl_writer = Some(Mutex::new(ctrl_writer));
182*cf78ab8cSAndroid Build Coastguard Worker         let (data_listener, data_reader, data_writer) =
183*cf78ab8cSAndroid Build Coastguard Worker             self.create_pipe().expect("Failed to create data pipe");
184*cf78ab8cSAndroid Build Coastguard Worker         self.data_writer = Some(Mutex::new(data_writer));
185*cf78ab8cSAndroid Build Coastguard Worker 
186*cf78ab8cSAndroid Build Coastguard Worker         // Start hostapd thread
187*cf78ab8cSAndroid Build Coastguard Worker         let verbose = self.verbose;
188*cf78ab8cSAndroid Build Coastguard Worker         let config_path = self.config_path.to_string_lossy().into_owned();
189*cf78ab8cSAndroid Build Coastguard Worker         *self.handle.write().unwrap() = Some(
190*cf78ab8cSAndroid Build Coastguard Worker             thread::Builder::new()
191*cf78ab8cSAndroid Build Coastguard Worker                 .name("hostapd".to_string())
192*cf78ab8cSAndroid Build Coastguard Worker                 .spawn(move || Self::hostapd_thread(verbose, config_path))
193*cf78ab8cSAndroid Build Coastguard Worker                 .expect("Failed to spawn Hostapd thread"),
194*cf78ab8cSAndroid Build Coastguard Worker         );
195*cf78ab8cSAndroid Build Coastguard Worker 
196*cf78ab8cSAndroid Build Coastguard Worker         // Start hostapd response thread
197*cf78ab8cSAndroid Build Coastguard Worker         let tx_bytes = self.tx_bytes.clone();
198*cf78ab8cSAndroid Build Coastguard Worker         let runtime = Arc::clone(&self.runtime);
199*cf78ab8cSAndroid Build Coastguard Worker         let _ = thread::Builder::new()
200*cf78ab8cSAndroid Build Coastguard Worker             .name("hostapd_response".to_string())
201*cf78ab8cSAndroid Build Coastguard Worker             .spawn(move || {
202*cf78ab8cSAndroid Build Coastguard Worker                 Self::hostapd_response_thread(
203*cf78ab8cSAndroid Build Coastguard Worker                     data_listener,
204*cf78ab8cSAndroid Build Coastguard Worker                     ctrl_listener,
205*cf78ab8cSAndroid Build Coastguard Worker                     data_reader,
206*cf78ab8cSAndroid Build Coastguard Worker                     tx_bytes,
207*cf78ab8cSAndroid Build Coastguard Worker                     runtime,
208*cf78ab8cSAndroid Build Coastguard Worker                 );
209*cf78ab8cSAndroid Build Coastguard Worker             })
210*cf78ab8cSAndroid Build Coastguard Worker             .expect("Failed to spawn hostapd_response thread");
211*cf78ab8cSAndroid Build Coastguard Worker 
212*cf78ab8cSAndroid Build Coastguard Worker         true
213*cf78ab8cSAndroid Build Coastguard Worker     }
214*cf78ab8cSAndroid Build Coastguard Worker 
215*cf78ab8cSAndroid Build Coastguard Worker     /// Reconfigures `Hostapd` with the specified SSID (and password).
216*cf78ab8cSAndroid Build Coastguard Worker     ///
217*cf78ab8cSAndroid Build Coastguard Worker     /// TODO:
218*cf78ab8cSAndroid Build Coastguard Worker     /// * implement password & encryption support
219*cf78ab8cSAndroid Build Coastguard Worker     /// * update as async fn.
set_ssid( &mut self, ssid: impl Into<String>, password: impl Into<String>, ) -> anyhow::Result<()>220*cf78ab8cSAndroid Build Coastguard Worker     pub fn set_ssid(
221*cf78ab8cSAndroid Build Coastguard Worker         &mut self,
222*cf78ab8cSAndroid Build Coastguard Worker         ssid: impl Into<String>,
223*cf78ab8cSAndroid Build Coastguard Worker         password: impl Into<String>,
224*cf78ab8cSAndroid Build Coastguard Worker     ) -> anyhow::Result<()> {
225*cf78ab8cSAndroid Build Coastguard Worker         let ssid = ssid.into();
226*cf78ab8cSAndroid Build Coastguard Worker         let password = password.into();
227*cf78ab8cSAndroid Build Coastguard Worker         if ssid.is_empty() {
228*cf78ab8cSAndroid Build Coastguard Worker             bail!("set_ssid must have a non-empty SSID");
229*cf78ab8cSAndroid Build Coastguard Worker         }
230*cf78ab8cSAndroid Build Coastguard Worker 
231*cf78ab8cSAndroid Build Coastguard Worker         if !password.is_empty() {
232*cf78ab8cSAndroid Build Coastguard Worker             bail!("set_ssid with password is not yet supported.");
233*cf78ab8cSAndroid Build Coastguard Worker         }
234*cf78ab8cSAndroid Build Coastguard Worker 
235*cf78ab8cSAndroid Build Coastguard Worker         if ssid == self.get_ssid() && password == self.get_config_val("password") {
236*cf78ab8cSAndroid Build Coastguard Worker             info!("SSID and password matches current configuration.");
237*cf78ab8cSAndroid Build Coastguard Worker             return Ok(());
238*cf78ab8cSAndroid Build Coastguard Worker         }
239*cf78ab8cSAndroid Build Coastguard Worker 
240*cf78ab8cSAndroid Build Coastguard Worker         // Update the config
241*cf78ab8cSAndroid Build Coastguard Worker         self.config.insert("ssid".to_string(), ssid);
242*cf78ab8cSAndroid Build Coastguard Worker         if !password.is_empty() {
243*cf78ab8cSAndroid Build Coastguard Worker             let password_config = [
244*cf78ab8cSAndroid Build Coastguard Worker                 ("wpa", "2"),
245*cf78ab8cSAndroid Build Coastguard Worker                 ("wpa_key_mgmt", "WPA-PSK"),
246*cf78ab8cSAndroid Build Coastguard Worker                 ("rsn_pairwise", "CCMP"),
247*cf78ab8cSAndroid Build Coastguard Worker                 ("wpa_passphrase", &password),
248*cf78ab8cSAndroid Build Coastguard Worker             ];
249*cf78ab8cSAndroid Build Coastguard Worker             self.config.extend(password_config.iter().map(|(k, v)| (k.to_string(), v.to_string())));
250*cf78ab8cSAndroid Build Coastguard Worker         }
251*cf78ab8cSAndroid Build Coastguard Worker 
252*cf78ab8cSAndroid Build Coastguard Worker         // Update the config file.
253*cf78ab8cSAndroid Build Coastguard Worker         self.gen_config_file()?;
254*cf78ab8cSAndroid Build Coastguard Worker 
255*cf78ab8cSAndroid Build Coastguard Worker         // Send command for Hostapd to reload config file
256*cf78ab8cSAndroid Build Coastguard Worker         if let Err(e) = self.runtime.block_on(Self::async_write(
257*cf78ab8cSAndroid Build Coastguard Worker             self.ctrl_writer.as_ref().unwrap(),
258*cf78ab8cSAndroid Build Coastguard Worker             c_string_to_bytes(VIRTIO_WIFI_CTRL_CMD_RELOAD_CONFIG),
259*cf78ab8cSAndroid Build Coastguard Worker         )) {
260*cf78ab8cSAndroid Build Coastguard Worker             bail!("Failed to send VIRTIO_WIFI_CTRL_CMD_RELOAD_CONFIG to hostapd to reload config: {:?}", e);
261*cf78ab8cSAndroid Build Coastguard Worker         }
262*cf78ab8cSAndroid Build Coastguard Worker 
263*cf78ab8cSAndroid Build Coastguard Worker         Ok(())
264*cf78ab8cSAndroid Build Coastguard Worker     }
265*cf78ab8cSAndroid Build Coastguard Worker 
266*cf78ab8cSAndroid Build Coastguard Worker     /// Retrieves the current SSID in the `Hostapd` configuration.
get_ssid(&self) -> String267*cf78ab8cSAndroid Build Coastguard Worker     pub fn get_ssid(&self) -> String {
268*cf78ab8cSAndroid Build Coastguard Worker         self.get_config_val("ssid")
269*cf78ab8cSAndroid Build Coastguard Worker     }
270*cf78ab8cSAndroid Build Coastguard Worker 
271*cf78ab8cSAndroid Build Coastguard Worker     /// Retrieves the `Hostapd`'s BSSID.
get_bssid(&self) -> MacAddress272*cf78ab8cSAndroid Build Coastguard Worker     pub fn get_bssid(&self) -> MacAddress {
273*cf78ab8cSAndroid Build Coastguard Worker         self.bssid
274*cf78ab8cSAndroid Build Coastguard Worker     }
275*cf78ab8cSAndroid Build Coastguard Worker 
276*cf78ab8cSAndroid Build Coastguard Worker     /// Attempt to encrypt the given IEEE 802.11 frame.
try_encrypt(&self, _ieee80211: &Ieee80211) -> Option<Ieee80211>277*cf78ab8cSAndroid Build Coastguard Worker     pub fn try_encrypt(&self, _ieee80211: &Ieee80211) -> Option<Ieee80211> {
278*cf78ab8cSAndroid Build Coastguard Worker         // TODO
279*cf78ab8cSAndroid Build Coastguard Worker         None
280*cf78ab8cSAndroid Build Coastguard Worker     }
281*cf78ab8cSAndroid Build Coastguard Worker 
282*cf78ab8cSAndroid Build Coastguard Worker     /// Attempt to decrypt the given IEEE 802.11 frame.
try_decrypt(&self, _ieee80211: &Ieee80211) -> Option<Ieee80211>283*cf78ab8cSAndroid Build Coastguard Worker     pub fn try_decrypt(&self, _ieee80211: &Ieee80211) -> Option<Ieee80211> {
284*cf78ab8cSAndroid Build Coastguard Worker         // TODO
285*cf78ab8cSAndroid Build Coastguard Worker         None
286*cf78ab8cSAndroid Build Coastguard Worker     }
287*cf78ab8cSAndroid Build Coastguard Worker 
288*cf78ab8cSAndroid Build Coastguard Worker     /// Inputs data packet bytes from netsim to `hostapd`.
289*cf78ab8cSAndroid Build Coastguard Worker     ///
290*cf78ab8cSAndroid Build Coastguard Worker     /// TODO:
291*cf78ab8cSAndroid Build Coastguard Worker     /// * update as async fn.
input(&self, bytes: Bytes) -> anyhow::Result<()>292*cf78ab8cSAndroid Build Coastguard Worker     pub fn input(&self, bytes: Bytes) -> anyhow::Result<()> {
293*cf78ab8cSAndroid Build Coastguard Worker         // Make sure hostapd is already running
294*cf78ab8cSAndroid Build Coastguard Worker         assert!(self.is_running(), "Failed to send input. Hostapd is not running.");
295*cf78ab8cSAndroid Build Coastguard Worker         self.runtime.block_on(Self::async_write(self.data_writer.as_ref().unwrap(), &bytes))
296*cf78ab8cSAndroid Build Coastguard Worker     }
297*cf78ab8cSAndroid Build Coastguard Worker 
298*cf78ab8cSAndroid Build Coastguard Worker     /// Checks whether the `hostapd` thread is running.
is_running(&self) -> bool299*cf78ab8cSAndroid Build Coastguard Worker     pub fn is_running(&self) -> bool {
300*cf78ab8cSAndroid Build Coastguard Worker         let handle_lock = self.handle.read().unwrap();
301*cf78ab8cSAndroid Build Coastguard Worker         handle_lock.is_some() && !handle_lock.as_ref().unwrap().is_finished()
302*cf78ab8cSAndroid Build Coastguard Worker     }
303*cf78ab8cSAndroid Build Coastguard Worker 
304*cf78ab8cSAndroid Build Coastguard Worker     /// Terminates the `Hostapd` process thread by sending a control command.
terminate(&self)305*cf78ab8cSAndroid Build Coastguard Worker     pub fn terminate(&self) {
306*cf78ab8cSAndroid Build Coastguard Worker         if !self.is_running() {
307*cf78ab8cSAndroid Build Coastguard Worker             warn!("hostapd terminate() called when hostapd thread is not running");
308*cf78ab8cSAndroid Build Coastguard Worker             return;
309*cf78ab8cSAndroid Build Coastguard Worker         }
310*cf78ab8cSAndroid Build Coastguard Worker 
311*cf78ab8cSAndroid Build Coastguard Worker         // Send terminate command to hostapd
312*cf78ab8cSAndroid Build Coastguard Worker         if let Err(e) = self.runtime.block_on(Self::async_write(
313*cf78ab8cSAndroid Build Coastguard Worker             self.ctrl_writer.as_ref().unwrap(),
314*cf78ab8cSAndroid Build Coastguard Worker             c_string_to_bytes(VIRTIO_WIFI_CTRL_CMD_TERMINATE),
315*cf78ab8cSAndroid Build Coastguard Worker         )) {
316*cf78ab8cSAndroid Build Coastguard Worker             warn!("Failed to send VIRTIO_WIFI_CTRL_CMD_TERMINATE to hostapd to terminate: {:?}", e);
317*cf78ab8cSAndroid Build Coastguard Worker         }
318*cf78ab8cSAndroid Build Coastguard Worker     }
319*cf78ab8cSAndroid Build Coastguard Worker 
320*cf78ab8cSAndroid Build Coastguard Worker     /// Generates the `hostapd.conf` file in the discovery directory.
gen_config_file(&self) -> anyhow::Result<()>321*cf78ab8cSAndroid Build Coastguard Worker     fn gen_config_file(&self) -> anyhow::Result<()> {
322*cf78ab8cSAndroid Build Coastguard Worker         let conf_file = File::create(self.config_path.clone())?; // Create or overwrite the file
323*cf78ab8cSAndroid Build Coastguard Worker         let mut writer = BufWriter::new(conf_file);
324*cf78ab8cSAndroid Build Coastguard Worker 
325*cf78ab8cSAndroid Build Coastguard Worker         for (key, value) in &self.config {
326*cf78ab8cSAndroid Build Coastguard Worker             writeln!(&mut writer, "{}={}", key, value)?;
327*cf78ab8cSAndroid Build Coastguard Worker         }
328*cf78ab8cSAndroid Build Coastguard Worker 
329*cf78ab8cSAndroid Build Coastguard Worker         Ok(writer.flush()?) // Ensure all data is written to the file
330*cf78ab8cSAndroid Build Coastguard Worker     }
331*cf78ab8cSAndroid Build Coastguard Worker 
332*cf78ab8cSAndroid Build Coastguard Worker     /// Gets the value of the given key in the config.
333*cf78ab8cSAndroid Build Coastguard Worker     ///
334*cf78ab8cSAndroid Build Coastguard Worker     /// Returns an empty String if the key is not found.
get_config_val(&self, key: &str) -> String335*cf78ab8cSAndroid Build Coastguard Worker     fn get_config_val(&self, key: &str) -> String {
336*cf78ab8cSAndroid Build Coastguard Worker         self.config.get(key).cloned().unwrap_or_default()
337*cf78ab8cSAndroid Build Coastguard Worker     }
338*cf78ab8cSAndroid Build Coastguard Worker 
339*cf78ab8cSAndroid Build Coastguard Worker     /// Creates a pipe of two connected `TcpStream` objects.
340*cf78ab8cSAndroid Build Coastguard Worker     ///
341*cf78ab8cSAndroid Build Coastguard Worker     /// Extracts the first stream's raw descriptor and splits the second stream
342*cf78ab8cSAndroid Build Coastguard Worker     /// into `OwnedReadHalf` and `OwnedWriteHalf`.
343*cf78ab8cSAndroid Build Coastguard Worker     ///
344*cf78ab8cSAndroid Build Coastguard Worker     /// # Returns
345*cf78ab8cSAndroid Build Coastguard Worker     ///
346*cf78ab8cSAndroid Build Coastguard Worker     /// * `Ok((listener, read_half, write_half))` if the pipe creation is successful.
347*cf78ab8cSAndroid Build Coastguard Worker     /// * `Err(std::io::Error)` if an error occurs during pipe creation.
create_pipe( &self, ) -> anyhow::Result<(RawDescriptor, OwnedReadHalf, OwnedWriteHalf), std::io::Error>348*cf78ab8cSAndroid Build Coastguard Worker     fn create_pipe(
349*cf78ab8cSAndroid Build Coastguard Worker         &self,
350*cf78ab8cSAndroid Build Coastguard Worker     ) -> anyhow::Result<(RawDescriptor, OwnedReadHalf, OwnedWriteHalf), std::io::Error> {
351*cf78ab8cSAndroid Build Coastguard Worker         let (listener, stream) = self.runtime.block_on(Self::async_create_pipe())?;
352*cf78ab8cSAndroid Build Coastguard Worker         let listener = into_raw_descriptor(listener);
353*cf78ab8cSAndroid Build Coastguard Worker         let (read_half, write_half) = stream.into_split();
354*cf78ab8cSAndroid Build Coastguard Worker         Ok((listener, read_half, write_half))
355*cf78ab8cSAndroid Build Coastguard Worker     }
356*cf78ab8cSAndroid Build Coastguard Worker 
357*cf78ab8cSAndroid Build Coastguard Worker     /// Creates a pipe asynchronously.
async_create_pipe() -> anyhow::Result<(TcpStream, TcpStream), std::io::Error>358*cf78ab8cSAndroid Build Coastguard Worker     async fn async_create_pipe() -> anyhow::Result<(TcpStream, TcpStream), std::io::Error> {
359*cf78ab8cSAndroid Build Coastguard Worker         let listener = match TcpListener::bind(SocketAddr::from((Ipv4Addr::LOCALHOST, 0))).await {
360*cf78ab8cSAndroid Build Coastguard Worker             Ok(listener) => listener,
361*cf78ab8cSAndroid Build Coastguard Worker             Err(e) => {
362*cf78ab8cSAndroid Build Coastguard Worker                 // Support hosts that only have IPv6
363*cf78ab8cSAndroid Build Coastguard Worker                 info!("Failed to bind to 127.0.0.1:0. Try to bind to [::1]:0 next. Err: {:?}", e);
364*cf78ab8cSAndroid Build Coastguard Worker                 TcpListener::bind(SocketAddr::from((Ipv6Addr::LOCALHOST, 0))).await?
365*cf78ab8cSAndroid Build Coastguard Worker             }
366*cf78ab8cSAndroid Build Coastguard Worker         };
367*cf78ab8cSAndroid Build Coastguard Worker         let addr = listener.local_addr()?;
368*cf78ab8cSAndroid Build Coastguard Worker         let stream = TcpStream::connect(addr).await?;
369*cf78ab8cSAndroid Build Coastguard Worker         let (listener, _) = listener.accept().await?;
370*cf78ab8cSAndroid Build Coastguard Worker         Ok((listener, stream))
371*cf78ab8cSAndroid Build Coastguard Worker     }
372*cf78ab8cSAndroid Build Coastguard Worker 
373*cf78ab8cSAndroid Build Coastguard Worker     /// Writes data to a writer asynchronously.
async_write(writer: &Mutex<OwnedWriteHalf>, data: &[u8]) -> anyhow::Result<()>374*cf78ab8cSAndroid Build Coastguard Worker     async fn async_write(writer: &Mutex<OwnedWriteHalf>, data: &[u8]) -> anyhow::Result<()> {
375*cf78ab8cSAndroid Build Coastguard Worker         let mut writer_guard = writer.lock().await;
376*cf78ab8cSAndroid Build Coastguard Worker         writer_guard.write_all(data).await?;
377*cf78ab8cSAndroid Build Coastguard Worker         writer_guard.flush().await?;
378*cf78ab8cSAndroid Build Coastguard Worker         Ok(())
379*cf78ab8cSAndroid Build Coastguard Worker     }
380*cf78ab8cSAndroid Build Coastguard Worker 
381*cf78ab8cSAndroid Build Coastguard Worker     /// Runs the C `hostapd` process with `run_hostapd_main`.
382*cf78ab8cSAndroid Build Coastguard Worker     ///
383*cf78ab8cSAndroid Build Coastguard Worker     /// This function is meant to be spawned in a separate thread.
hostapd_thread(verbose: bool, config_path: String)384*cf78ab8cSAndroid Build Coastguard Worker     fn hostapd_thread(verbose: bool, config_path: String) {
385*cf78ab8cSAndroid Build Coastguard Worker         let mut args = vec![CString::new("hostapd").unwrap()];
386*cf78ab8cSAndroid Build Coastguard Worker         if verbose {
387*cf78ab8cSAndroid Build Coastguard Worker             args.push(CString::new("-dddd").unwrap());
388*cf78ab8cSAndroid Build Coastguard Worker         }
389*cf78ab8cSAndroid Build Coastguard Worker         args.push(
390*cf78ab8cSAndroid Build Coastguard Worker             CString::new(config_path.clone()).unwrap_or_else(|_| {
391*cf78ab8cSAndroid Build Coastguard Worker                 panic!("CString::new error on config file path: {}", config_path)
392*cf78ab8cSAndroid Build Coastguard Worker             }),
393*cf78ab8cSAndroid Build Coastguard Worker         );
394*cf78ab8cSAndroid Build Coastguard Worker         let argv: Vec<*const c_char> = args.iter().map(|arg| arg.as_ptr()).collect();
395*cf78ab8cSAndroid Build Coastguard Worker         let argc = argv.len() as c_int;
396*cf78ab8cSAndroid Build Coastguard Worker         // Safety: we ensure that argc is length of argv and argv.as_ptr() is a valid pointer of hostapd args
397*cf78ab8cSAndroid Build Coastguard Worker         unsafe { run_hostapd_main(argc, argv.as_ptr()) };
398*cf78ab8cSAndroid Build Coastguard Worker     }
399*cf78ab8cSAndroid Build Coastguard Worker 
400*cf78ab8cSAndroid Build Coastguard Worker     /// Sets the virtio (driver) data and control sockets.
set_virtio_driver_socket( data_descriptor: RawDescriptor, ctrl_descriptor: RawDescriptor, ) -> bool401*cf78ab8cSAndroid Build Coastguard Worker     fn set_virtio_driver_socket(
402*cf78ab8cSAndroid Build Coastguard Worker         data_descriptor: RawDescriptor,
403*cf78ab8cSAndroid Build Coastguard Worker         ctrl_descriptor: RawDescriptor,
404*cf78ab8cSAndroid Build Coastguard Worker     ) -> bool {
405*cf78ab8cSAndroid Build Coastguard Worker         // Safety: we ensure that data_descriptor and ctrl_descriptor are valid i32 raw file descriptor or socket
406*cf78ab8cSAndroid Build Coastguard Worker         unsafe {
407*cf78ab8cSAndroid Build Coastguard Worker             set_virtio_sock(data_descriptor) == 0 && set_virtio_ctrl_sock(ctrl_descriptor) == 0
408*cf78ab8cSAndroid Build Coastguard Worker         }
409*cf78ab8cSAndroid Build Coastguard Worker     }
410*cf78ab8cSAndroid Build Coastguard Worker 
411*cf78ab8cSAndroid Build Coastguard Worker     /// Manages reading `hostapd` responses and sending them via `tx_bytes`.
412*cf78ab8cSAndroid Build Coastguard Worker     ///
413*cf78ab8cSAndroid Build Coastguard Worker     /// The thread first attempts to set virtio driver sockets with retries until success.
414*cf78ab8cSAndroid Build Coastguard Worker     /// Next, the thread reads `hostapd` responses and writes them to netsim.
hostapd_response_thread( data_listener: RawDescriptor, ctrl_listener: RawDescriptor, mut data_reader: OwnedReadHalf, tx_bytes: mpsc::Sender<Bytes>, runtime: Arc<Runtime>, )415*cf78ab8cSAndroid Build Coastguard Worker     fn hostapd_response_thread(
416*cf78ab8cSAndroid Build Coastguard Worker         data_listener: RawDescriptor,
417*cf78ab8cSAndroid Build Coastguard Worker         ctrl_listener: RawDescriptor,
418*cf78ab8cSAndroid Build Coastguard Worker         mut data_reader: OwnedReadHalf,
419*cf78ab8cSAndroid Build Coastguard Worker         tx_bytes: mpsc::Sender<Bytes>,
420*cf78ab8cSAndroid Build Coastguard Worker         runtime: Arc<Runtime>,
421*cf78ab8cSAndroid Build Coastguard Worker     ) {
422*cf78ab8cSAndroid Build Coastguard Worker         let mut buf: [u8; 1500] = [0u8; 1500];
423*cf78ab8cSAndroid Build Coastguard Worker         loop {
424*cf78ab8cSAndroid Build Coastguard Worker             if !Self::set_virtio_driver_socket(data_listener, ctrl_listener) {
425*cf78ab8cSAndroid Build Coastguard Worker                 warn!("Unable to set virtio driver socket. Retrying...");
426*cf78ab8cSAndroid Build Coastguard Worker                 sleep(Duration::from_millis(250));
427*cf78ab8cSAndroid Build Coastguard Worker                 continue;
428*cf78ab8cSAndroid Build Coastguard Worker             };
429*cf78ab8cSAndroid Build Coastguard Worker             break;
430*cf78ab8cSAndroid Build Coastguard Worker         }
431*cf78ab8cSAndroid Build Coastguard Worker         loop {
432*cf78ab8cSAndroid Build Coastguard Worker             let size = match runtime.block_on(async { data_reader.read(&mut buf[..]).await }) {
433*cf78ab8cSAndroid Build Coastguard Worker                 Ok(size) => size,
434*cf78ab8cSAndroid Build Coastguard Worker                 Err(e) => {
435*cf78ab8cSAndroid Build Coastguard Worker                     warn!("Failed to read hostapd response: {:?}", e);
436*cf78ab8cSAndroid Build Coastguard Worker                     break;
437*cf78ab8cSAndroid Build Coastguard Worker                 }
438*cf78ab8cSAndroid Build Coastguard Worker             };
439*cf78ab8cSAndroid Build Coastguard Worker 
440*cf78ab8cSAndroid Build Coastguard Worker             if let Err(e) = tx_bytes.send(Bytes::copy_from_slice(&buf[..size])) {
441*cf78ab8cSAndroid Build Coastguard Worker                 warn!("Failed to send hostapd packet response: {:?}", e);
442*cf78ab8cSAndroid Build Coastguard Worker                 break;
443*cf78ab8cSAndroid Build Coastguard Worker             };
444*cf78ab8cSAndroid Build Coastguard Worker         }
445*cf78ab8cSAndroid Build Coastguard Worker     }
446*cf78ab8cSAndroid Build Coastguard Worker }
447*cf78ab8cSAndroid Build Coastguard Worker 
448*cf78ab8cSAndroid Build Coastguard Worker impl Drop for Hostapd {
449*cf78ab8cSAndroid Build Coastguard Worker     /// Terminates the `hostapd` process when the `Hostapd` instance is dropped.
drop(&mut self)450*cf78ab8cSAndroid Build Coastguard Worker     fn drop(&mut self) {
451*cf78ab8cSAndroid Build Coastguard Worker         self.terminate();
452*cf78ab8cSAndroid Build Coastguard Worker     }
453*cf78ab8cSAndroid Build Coastguard Worker }
454*cf78ab8cSAndroid Build Coastguard Worker 
455*cf78ab8cSAndroid Build Coastguard Worker /// Converts a `TcpStream` to a `RawDescriptor` (i32).
into_raw_descriptor(stream: TcpStream) -> RawDescriptor456*cf78ab8cSAndroid Build Coastguard Worker fn into_raw_descriptor(stream: TcpStream) -> RawDescriptor {
457*cf78ab8cSAndroid Build Coastguard Worker     let std_stream = stream.into_std().expect("into_raw_descriptor's into_std() failed");
458*cf78ab8cSAndroid Build Coastguard Worker     // hostapd fd expects blocking, but rust set non-blocking for async
459*cf78ab8cSAndroid Build Coastguard Worker     std_stream.set_nonblocking(false).expect("non-blocking");
460*cf78ab8cSAndroid Build Coastguard Worker 
461*cf78ab8cSAndroid Build Coastguard Worker     // Use into_raw_fd for Unix to pass raw file descriptor to C
462*cf78ab8cSAndroid Build Coastguard Worker     #[cfg(unix)]
463*cf78ab8cSAndroid Build Coastguard Worker     return std_stream.into_raw_fd();
464*cf78ab8cSAndroid Build Coastguard Worker 
465*cf78ab8cSAndroid Build Coastguard Worker     // Use into_raw_socket for Windows to pass raw socket to C
466*cf78ab8cSAndroid Build Coastguard Worker     #[cfg(windows)]
467*cf78ab8cSAndroid Build Coastguard Worker     std_stream.into_raw_socket().try_into().expect("Failed to convert Raw Socket value into i32")
468*cf78ab8cSAndroid Build Coastguard Worker }
469*cf78ab8cSAndroid Build Coastguard Worker 
470*cf78ab8cSAndroid Build Coastguard Worker /// Converts a null-terminated c-string slice into `&[u8]` bytes without the null terminator.
c_string_to_bytes(c_string: &[u8]) -> &[u8]471*cf78ab8cSAndroid Build Coastguard Worker fn c_string_to_bytes(c_string: &[u8]) -> &[u8] {
472*cf78ab8cSAndroid Build Coastguard Worker     CStr::from_bytes_with_nul(c_string).unwrap().to_bytes()
473*cf78ab8cSAndroid Build Coastguard Worker }
474