Snap for 11973804 from 7db013bca868b5fe8e7086c761cd156a3f28573a to 24Q3-release

Change-Id: I1af176ea5ce1feac3975650324a9f840b8442342
diff --git a/Android.bp b/Android.bp
index 5ae785a..0d5654e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -145,14 +145,14 @@
 
 genrule {
     name: "netsim_netlink_rust_gen",
-    defaults: ["pdl_rust_legacy_generator_defaults"],
+    defaults: ["pdl_rust_generator_defaults"],
     srcs: ["pdl/netlink.pdl"],
     out: ["netlink_packets.rs"],
 }
 
 genrule {
     name: "netsim_mac80211_hwsim_rust_gen",
-    defaults: ["pdl_rust_legacy_generator_defaults"],
+    defaults: ["pdl_rust_generator_defaults"],
     srcs: ["pdl/mac80211_hwsim.pdl"],
     out: ["mac80211_hwsim_packets.rs"],
 }
diff --git a/pdl/CMakeLists.txt b/pdl/CMakeLists.txt
index 1f32cb6..4f1cedf 100644
--- a/pdl/CMakeLists.txt
+++ b/pdl/CMakeLists.txt
@@ -10,7 +10,7 @@
   OUTPUT
   netlink_packets.rs
   LANG
-  rust_legacy)
+  rust)
 
 pdl_gen(
   NAME
@@ -20,7 +20,7 @@
   OUTPUT
   mac80211_hwsim_packets.rs
   LANG
-  rust_legacy)
+  rust)
 
 pdl_gen(
   NAME
diff --git a/rust/daemon/src/devices/devices_handler.rs b/rust/daemon/src/devices/devices_handler.rs
index 5ad92eb..1707751 100644
--- a/rust/daemon/src/devices/devices_handler.rs
+++ b/rust/daemon/src/devices/devices_handler.rs
@@ -577,7 +577,7 @@
         .map_err(|e| anyhow::anyhow!("{e:?}"))
 }
 
-fn reset_all() -> Result<(), String> {
+pub fn reset_all() -> Result<(), String> {
     let manager = get_manager();
     // Perform reset for all manager
     for device in manager.devices.read().unwrap().values() {
@@ -627,8 +627,7 @@
     }
 }
 
-/// Performs ListDevices to get the list of DeviceManager and write to writer.
-fn handle_device_list(writer: ResponseWritable) {
+pub fn list_device() -> anyhow::Result<ListDeviceResponse, String> {
     // Instantiate ListDeviceResponse and add DeviceManager
     let mut response = ListDeviceResponse::new();
     let manager = get_manager();
@@ -645,7 +644,12 @@
         ..Default::default()
     })
     .into();
+    Ok(response)
+}
 
+/// Performs ListDevices to get the list of DeviceManager and write to writer.
+fn handle_device_list(writer: ResponseWritable) {
+    let response = list_device().unwrap();
     // Perform protobuf-json-mapping with the given protobuf
     if let Ok(json_response) = print_to_string_with_options(&response, &JSON_PRINT_OPTION) {
         writer.put_ok("text/json", &json_response, vec![])
diff --git a/rust/daemon/src/ffi.rs b/rust/daemon/src/ffi.rs
index f9b14f4..4caf77a 100644
--- a/rust/daemon/src/ffi.rs
+++ b/rust/daemon/src/ffi.rs
@@ -253,6 +253,14 @@
         #[namespace = "netsim::wifi"]
         fn HandleWifiRequestCxx(chip_id: u32, packet: &Vec<u8>);
 
+        #[rust_name = hostapd_send]
+        #[namespace = "netsim::wifi"]
+        fn HostapdSendCxx(chip_id: u32, packet: &Vec<u8>);
+
+        #[rust_name = libslirp_send]
+        #[namespace = "netsim::wifi"]
+        fn LibslirpSendCxx(chip_id: u32, packet: &Vec<u8>);
+
         #[namespace = "netsim::wifi"]
         pub fn libslirp_main_loop_wait();
 
diff --git a/rust/daemon/src/grpc_server/frontend.rs b/rust/daemon/src/grpc_server/frontend.rs
index 692ffcb..912df98 100644
--- a/rust/daemon/src/grpc_server/frontend.rs
+++ b/rust/daemon/src/grpc_server/frontend.rs
@@ -12,64 +12,71 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use crate::devices::devices_handler;
 use futures_util::{FutureExt as _, TryFutureExt as _};
-use grpcio::{RpcContext, UnarySink};
+use grpcio::{RpcContext, RpcStatus, RpcStatusCode, UnarySink};
+use log::warn;
 use netsim_proto::frontend::VersionResponse;
 use netsim_proto::frontend_grpc::FrontendService;
+use protobuf::well_known_types::empty::Empty;
 
 #[derive(Clone)]
 pub struct FrontendClient;
 
 impl FrontendService for FrontendClient {
-    fn get_version(
-        &mut self,
-        ctx: RpcContext<'_>,
-        req: protobuf::well_known_types::empty::Empty,
-        sink: UnarySink<VersionResponse>,
-    ) {
-        let response = VersionResponse {
-            version: "netsim test server version 0.0.1".to_string(),
-            ..Default::default()
-        };
+    fn get_version(&mut self, ctx: RpcContext<'_>, req: Empty, sink: UnarySink<VersionResponse>) {
+        let response =
+            VersionResponse { version: crate::version::get_version(), ..Default::default() };
         let f = sink
             .success(response)
-            .map_err(move |e| eprintln!("failed to reply {:?}: {:?}", req, e))
+            .map_err(move |e| eprintln!("client error {:?}: {:?}", req, e))
             .map(|_| ());
         ctx.spawn(f)
     }
 
     fn list_device(
         &mut self,
-        _ctx: grpcio::RpcContext,
-        _req: protobuf::well_known_types::empty::Empty,
-        _sink: grpcio::UnarySink<netsim_proto::frontend::ListDeviceResponse>,
+        ctx: grpcio::RpcContext,
+        req: Empty,
+        sink: grpcio::UnarySink<netsim_proto::frontend::ListDeviceResponse>,
     ) {
-        todo!()
+        let response = match devices_handler::list_device() {
+            Ok(response) => sink.success(response),
+            Err(e) => {
+                warn!("failed to list device: {}", e);
+                sink.fail(RpcStatus::with_message(RpcStatusCode::INTERNAL, e))
+            }
+        };
+
+        ctx.spawn(response.map_err(move |e| warn!("client error {:?}: {:?}", req, e)).map(|_| ()))
     }
 
     fn patch_device(
         &mut self,
         _ctx: grpcio::RpcContext,
         _req: netsim_proto::frontend::PatchDeviceRequest,
-        _sink: grpcio::UnarySink<protobuf::well_known_types::empty::Empty>,
+        _sink: grpcio::UnarySink<Empty>,
     ) {
         todo!()
     }
 
-    fn reset(
-        &mut self,
-        _ctx: grpcio::RpcContext,
-        _req: protobuf::well_known_types::empty::Empty,
-        _sink: grpcio::UnarySink<protobuf::well_known_types::empty::Empty>,
-    ) {
-        todo!()
+    fn reset(&mut self, ctx: grpcio::RpcContext, _req: Empty, sink: grpcio::UnarySink<Empty>) {
+        let response = match devices_handler::reset_all() {
+            Ok(_) => sink.success(Empty::new()),
+            Err(e) => {
+                warn!("failed to reset: {}", e);
+                sink.fail(RpcStatus::with_message(RpcStatusCode::INTERNAL, e))
+            }
+        };
+
+        ctx.spawn(response.map_err(move |e| warn!("client error: {:?}", e)).map(|_| ()))
     }
 
     fn patch_capture(
         &mut self,
         _ctx: grpcio::RpcContext,
         _req: netsim_proto::frontend::PatchCaptureRequest,
-        _sink: grpcio::UnarySink<protobuf::well_known_types::empty::Empty>,
+        _sink: grpcio::UnarySink<Empty>,
     ) {
         todo!()
     }
@@ -77,7 +84,7 @@
     fn list_capture(
         &mut self,
         _ctx: grpcio::RpcContext,
-        _req: protobuf::well_known_types::empty::Empty,
+        _req: Empty,
         _sink: grpcio::UnarySink<netsim_proto::frontend::ListCaptureResponse>,
     ) {
         todo!()
diff --git a/rust/daemon/src/ranging.rs b/rust/daemon/src/ranging.rs
index 9abd718..18bc6f7 100644
--- a/rust/daemon/src/ranging.rs
+++ b/rust/daemon/src/ranging.rs
@@ -108,9 +108,9 @@
 /// UWB Ranging Model for computing range, azimuth, and elevation
 /// The raning model brought from https://github.com/google/pica
 #[allow(unused)]
-pub fn compute_range_azimuth_elevation(a: &Pose, b: &Pose) -> anyhow::Result<(u16, i16, i8)> {
+pub fn compute_range_azimuth_elevation(a: &Pose, b: &Pose) -> anyhow::Result<(f32, i16, i8)> {
     let delta = b.position - a.position;
-    let distance = delta.length();
+    let distance = delta.length().clamp(0.0, u16::MAX as f32);
     let direction = a.orientation.mul_vec3(delta);
     let azimuth = azimuth(direction).to_degrees().round();
     let elevation = elevation(direction).to_degrees().round();
@@ -121,7 +121,7 @@
     if !(-90. ..=90.).contains(&elevation) {
         return Err(anyhow::anyhow!("elevation is not between -90 and 90. value: {elevation}"));
     }
-    Ok((f32::min(distance, u16::MAX as f32) as u16, azimuth as i16, elevation as i8))
+    Ok((distance, azimuth as i16, elevation as i8))
 }
 
 #[cfg(test)]
@@ -162,22 +162,22 @@
         {
             let b_pose = Pose::new(10.0, 0.0, 0.0, 0.0, 0.0, 0.0);
             let (range, _, _) = compute_range_azimuth_elevation(&a_pose, &b_pose).unwrap();
-            assert_eq!(range, 1000);
+            assert_eq!(range, 1000.);
         }
         {
             let b_pose = Pose::new(-10.0, 0.0, 0.0, 0.0, 0.0, 0.0);
             let (range, _, _) = compute_range_azimuth_elevation(&a_pose, &b_pose).unwrap();
-            assert_eq!(range, 1000);
+            assert_eq!(range, 1000.);
         }
         {
             let b_pose = Pose::new(10.0, 10.0, 0.0, 0.0, 0.0, 0.0);
             let (range, _, _) = compute_range_azimuth_elevation(&a_pose, &b_pose).unwrap();
-            assert_eq!(range, f32::sqrt(2000000.).round() as u16);
+            assert_eq!(range, f32::sqrt(2000000.));
         }
         {
             let b_pose = Pose::new(-10.0, -10.0, -10.0, 0.0, 0.0, 0.0);
             let (range, _, _) = compute_range_azimuth_elevation(&a_pose, &b_pose).unwrap();
-            assert_eq!(range, f32::sqrt(3000000.).round() as u16);
+            assert_eq!(range, f32::sqrt(3000000.));
         }
     }
 
diff --git a/rust/daemon/src/uwb/ranging_data.rs b/rust/daemon/src/uwb/ranging_data.rs
index c442d45..3050838 100644
--- a/rust/daemon/src/uwb/ranging_data.rs
+++ b/rust/daemon/src/uwb/ranging_data.rs
@@ -16,11 +16,11 @@
 
 use std::collections::BTreeMap;
 
-type TrueDistance = f64; // meters
-type EstimatedDistance = f64; // meters
+type TrueDistance = f32; // meters
+type EstimatedDistance = f32; // meters
 
 /// The data is organized as a `BTreeMap` for efficient lookup and interpolation.
-struct RangingDataSet {
+pub struct RangingDataSet {
     /// Stores ranging data in the form of (true distance, [estimated distances]) pairs.
     /// The map keys are true distances in u16 centimeters.
     data: BTreeMap<u16, Vec<EstimatedDistance>>,
@@ -33,8 +33,14 @@
     /// ranging sensor.
     pub fn new(ranging_data: Option<Vec<(TrueDistance, EstimatedDistance)>>) -> Self {
         // Use sample_ranging_data.csv if ranging_data is not provided.
-        let sample_ranging_data: Vec<(TrueDistance, EstimatedDistance)> =
+        #[allow(clippy::excessive_precision)]
+        let mut sample_ranging_data: Vec<(TrueDistance, EstimatedDistance)> =
             ranging_data.unwrap_or(include!("sample_ranging_data.csv"));
+        // Convert to centimeters as Pica uses centimeters for ranging units
+        sample_ranging_data = sample_ranging_data
+            .into_iter()
+            .map(|(true_dist, est_dist)| (true_dist * 100.0, est_dist * 100.0))
+            .collect::<Vec<(TrueDistance, EstimatedDistance)>>();
 
         // Process the sample_raning_data into BTreeMap
         let mut data: BTreeMap<u16, Vec<EstimatedDistance>> = BTreeMap::new();
@@ -84,9 +90,9 @@
         let upper = self.data.range(&distance_u16..).next();
         match (lower, upper) {
             (Some((lower_key, lower_vals)), Some((upper_key, upper_vals))) => {
-                let x1 = *lower_key as f64 / 100.0;
+                let x1 = *lower_key as f32 / 100.0;
                 let y1 = *lower_vals.choose(&mut rng).unwrap();
-                let x2 = *upper_key as f64 / 100.0;
+                let x2 = *upper_key as f32 / 100.0;
                 let y2 = *upper_vals.choose(&mut rng).unwrap();
                 y1 + (distance - x1) * (y2 - y1) / (x2 - x1)
             }
@@ -108,10 +114,10 @@
     fn test_sample_ranging_data_set() {
         let ranging_data_set = sample_ranging_data_set();
         // Linear Interpolation
-        assert_eq!(ranging_data_set.sample(0.5, None), 0.55);
+        assert_eq!(ranging_data_set.sample(50., None), 55.);
         // Exact distance found in dataset
-        assert!([1.9, 2.1].contains(&ranging_data_set.sample(2.0, None)));
+        assert!([190., 210.].contains(&ranging_data_set.sample(200., None)));
         // Out of Range
-        assert_eq!(ranging_data_set.sample(3.0, None), 3.0);
+        assert_eq!(ranging_data_set.sample(300., None), 300.);
     }
 }
diff --git a/rust/daemon/src/uwb/ranging_estimator.rs b/rust/daemon/src/uwb/ranging_estimator.rs
index ede8777..fb4a91d 100644
--- a/rust/daemon/src/uwb/ranging_estimator.rs
+++ b/rust/daemon/src/uwb/ranging_estimator.rs
@@ -18,6 +18,7 @@
 
 use crate::devices::{chip::ChipIdentifier, devices_handler::get_device};
 use crate::ranging::{compute_range_azimuth_elevation, Pose};
+use crate::uwb::ranging_data::RangingDataSet;
 
 use std::collections::HashMap;
 use std::sync::{Arc, Mutex, MutexGuard};
@@ -54,11 +55,12 @@
 // Netsim's UwbRangingEstimator
 pub struct UwbRangingEstimator {
     shared_state: SharedState,
+    data_set: RangingDataSet,
 }
 
 impl UwbRangingEstimator {
     pub fn new(shared_state: SharedState) -> Self {
-        UwbRangingEstimator { shared_state }
+        UwbRangingEstimator { shared_state, data_set: RangingDataSet::new(None) }
     }
 
     // Utility to convert the UWB Chip handle into the device and chip_id.
@@ -86,7 +88,11 @@
         let a_pose = Pose::new(a_p.x, a_p.y, a_p.z, a_o.yaw, a_o.pitch, a_o.roll);
         let b_pose = Pose::new(b_p.x, b_p.y, b_p.z, b_o.yaw, b_o.pitch, b_o.roll);
         compute_range_azimuth_elevation(&a_pose, &b_pose)
-            .map(|(range, azimuth, elevation)| RangingMeasurement { range, azimuth, elevation })
+            .map(|(range, azimuth, elevation)| RangingMeasurement {
+                range: self.data_set.sample(range, None).round() as u16,
+                azimuth,
+                elevation,
+            })
             .map_err(|e| error!("{e:?}"))
             .ok()
     }
diff --git a/rust/daemon/src/wifi/frame.rs b/rust/daemon/src/wifi/frame.rs
index 8ef6775..00acb98 100644
--- a/rust/daemon/src/wifi/frame.rs
+++ b/rust/daemon/src/wifi/frame.rs
@@ -48,10 +48,10 @@
     // found.
     pub fn parse(msg: &HwsimMsg) -> anyhow::Result<Frame> {
         // Only expected to be called with HwsimCmd::Frame
-        if msg.get_hwsim_hdr().hwsim_cmd != HwsimCmd::Frame {
+        if msg.hwsim_hdr.hwsim_cmd != HwsimCmd::Frame {
             panic!("Invalid hwsim_cmd");
         }
-        let attrs = HwsimAttrSet::parse(msg.get_attributes()).context("HwsimAttrSet")?;
+        let attrs = HwsimAttrSet::parse(&msg.attributes).context("HwsimAttrSet")?;
         let frame = attrs.frame.clone().context("Frame")?;
         let ieee80211 = Ieee80211::decode_full(&frame).context("Ieee80211")?;
         // Required attributes are unwrapped and return an error if
diff --git a/rust/daemon/src/wifi/hwsim_attr_set.rs b/rust/daemon/src/wifi/hwsim_attr_set.rs
index bb87f06..cd64cb6 100644
--- a/rust/daemon/src/wifi/hwsim_attr_set.rs
+++ b/rust/daemon/src/wifi/hwsim_attr_set.rs
@@ -17,7 +17,7 @@
 use super::packets::ieee80211::MacAddress;
 use super::packets::mac80211_hwsim::{self, HwsimAttr, HwsimAttrChild::*, TxRate, TxRateFlag};
 use super::packets::netlink::NlAttrHdr;
-use anyhow::anyhow;
+use anyhow::{anyhow, Context};
 use pdl_runtime::Packet;
 use std::option::Option;
 
@@ -103,98 +103,81 @@
     }
 
     pub fn transmitter(&mut self, transmitter: &[u8; 6]) -> &mut Self {
-        self.extend_attributes(
-            mac80211_hwsim::HwsimAttrAddrTransmitterBuilder {
-                address: *transmitter,
-                nla_m: 0,
-                nla_o: 0,
-            }
-            .build(),
-        );
+        self.extend_attributes(mac80211_hwsim::HwsimAttrAddrTransmitter {
+            address: *transmitter,
+            nla_m: 0,
+            nla_o: 0,
+        });
         self.transmitter = Some(MacAddress::from(transmitter));
         self
     }
 
     pub fn receiver(&mut self, receiver: &[u8; 6]) -> &mut Self {
-        self.extend_attributes(
-            mac80211_hwsim::HwsimAttrAddrReceiverBuilder { address: *receiver, nla_m: 0, nla_o: 0 }
-                .build(),
-        );
+        self.extend_attributes(mac80211_hwsim::HwsimAttrAddrReceiver {
+            address: *receiver,
+            nla_m: 0,
+            nla_o: 0,
+        });
         self.receiver = Some(MacAddress::from(receiver));
         self
     }
 
     pub fn frame(&mut self, frame: &[u8]) -> &mut Self {
-        self.extend_attributes(
-            mac80211_hwsim::HwsimAttrFrameBuilder { data: (*frame).to_vec(), nla_m: 0, nla_o: 0 }
-                .build(),
-        );
+        self.extend_attributes(mac80211_hwsim::HwsimAttrFrame {
+            data: (*frame).to_vec(),
+            nla_m: 0,
+            nla_o: 0,
+        });
         self.frame = Some(frame.to_vec());
         self
     }
 
     pub fn flags(&mut self, flags: u32) -> &mut Self {
-        self.extend_attributes(
-            mac80211_hwsim::HwsimAttrFlagsBuilder { flags, nla_m: 0, nla_o: 0 }.build(),
-        );
+        self.extend_attributes(mac80211_hwsim::HwsimAttrFlags { flags, nla_m: 0, nla_o: 0 });
         self.flags = Some(flags);
         self
     }
 
     pub fn rx_rate(&mut self, rx_rate_idx: u32) -> &mut Self {
-        self.extend_attributes(
-            mac80211_hwsim::HwsimAttrRxRateBuilder { rx_rate_idx, nla_m: 0, nla_o: 0 }.build(),
-        );
+        self.extend_attributes(mac80211_hwsim::HwsimAttrRxRate { rx_rate_idx, nla_m: 0, nla_o: 0 });
         self.rx_rate_idx = Some(rx_rate_idx);
         self
     }
 
     pub fn signal(&mut self, signal: u32) -> &mut Self {
-        self.extend_attributes(
-            mac80211_hwsim::HwsimAttrSignalBuilder { signal, nla_m: 0, nla_o: 0 }.build(),
-        );
+        self.extend_attributes(mac80211_hwsim::HwsimAttrSignal { signal, nla_m: 0, nla_o: 0 });
         self.signal = Some(signal);
         self
     }
 
     pub fn cookie(&mut self, cookie: u64) -> &mut Self {
-        self.extend_attributes(
-            mac80211_hwsim::HwsimAttrCookieBuilder { cookie, nla_m: 0, nla_o: 0 }.build(),
-        );
+        self.extend_attributes(mac80211_hwsim::HwsimAttrCookie { cookie, nla_m: 0, nla_o: 0 });
         self.cookie = Some(cookie);
         self
     }
 
     pub fn freq(&mut self, freq: u32) -> &mut Self {
-        self.extend_attributes(
-            mac80211_hwsim::HwsimAttrFreqBuilder { freq, nla_m: 0, nla_o: 0 }.build(),
-        );
+        self.extend_attributes(mac80211_hwsim::HwsimAttrFreq { freq, nla_m: 0, nla_o: 0 });
         self.freq = Some(freq);
         self
     }
 
     pub fn tx_info(&mut self, tx_info: &[TxRate]) -> &mut Self {
-        self.extend_attributes(
-            mac80211_hwsim::HwsimAttrTxInfoBuilder {
-                tx_rates: (*tx_info).to_vec(),
-                nla_m: 0,
-                nla_o: 0,
-            }
-            .build(),
-        );
+        self.extend_attributes(mac80211_hwsim::HwsimAttrTxInfo {
+            tx_rates: (*tx_info).to_vec(),
+            nla_m: 0,
+            nla_o: 0,
+        });
         self.tx_info = Some(tx_info.to_vec());
         self
     }
 
     pub fn tx_info_flags(&mut self, tx_rate_flags: &[TxRateFlag]) -> &mut Self {
-        self.extend_attributes(
-            mac80211_hwsim::HwsimAttrTxInfoFlagsBuilder {
-                tx_rate_flags: (*tx_rate_flags).to_vec(),
-                nla_m: 0,
-                nla_o: 0,
-            }
-            .build(),
-        );
+        self.extend_attributes(mac80211_hwsim::HwsimAttrTxInfoFlags {
+            tx_rate_flags: (*tx_rate_flags).to_vec(),
+            nla_m: 0,
+            nla_o: 0,
+        });
         self.tx_info_flags = Some(tx_rate_flags.to_vec());
         self
     }
@@ -267,28 +250,29 @@
         let mut builder = HwsimAttrSet::builder();
         while index < attributes.len() {
             // Parse a generic netlink attribute to get the size
-            let nla_hdr = NlAttrHdr::parse(&attributes[index..index + 4]).unwrap();
+            let nla_hdr =
+                NlAttrHdr::decode_full(&attributes[index..index + 4]).context("NlAttrHdr")?;
             let nla_len = nla_hdr.nla_len as usize;
             // Now parse a single attribute at a time from the
             // attributes to allow padding per attribute.
-            let hwsim_attr = HwsimAttr::parse(&attributes[index..index + nla_len])?;
-            match hwsim_attr.specialize() {
+            let hwsim_attr = HwsimAttr::decode_full(&attributes[index..index + nla_len])?;
+            match hwsim_attr.specialize().context("HwsimAttr")? {
                 HwsimAttrAddrTransmitter(child) => {
-                    builder.transmitter(transmitter.unwrap_or(child.get_address()))
+                    builder.transmitter(transmitter.unwrap_or(child.address()))
                 }
-                HwsimAttrAddrReceiver(child) => builder.receiver(child.get_address()),
-                HwsimAttrFrame(child) => builder.frame(frame.unwrap_or(child.get_data())),
-                HwsimAttrFlags(child) => builder.flags(child.get_flags()),
-                HwsimAttrRxRate(child) => builder.rx_rate(child.get_rx_rate_idx()),
-                HwsimAttrSignal(child) => builder.signal(child.get_signal()),
-                HwsimAttrCookie(child) => builder.cookie(child.get_cookie()),
-                HwsimAttrFreq(child) => builder.freq(child.get_freq()),
-                HwsimAttrTxInfo(child) => builder.tx_info(child.get_tx_rates()),
-                HwsimAttrTxInfoFlags(child) => builder.tx_info_flags(child.get_tx_rate_flags()),
+                HwsimAttrAddrReceiver(child) => builder.receiver(&child.address),
+                HwsimAttrFrame(child) => builder.frame(frame.unwrap_or(&child.data)),
+                HwsimAttrFlags(child) => builder.flags(child.flags),
+                HwsimAttrRxRate(child) => builder.rx_rate(child.rx_rate_idx),
+                HwsimAttrSignal(child) => builder.signal(child.signal),
+                HwsimAttrCookie(child) => builder.cookie(child.cookie),
+                HwsimAttrFreq(child) => builder.freq(child.freq),
+                HwsimAttrTxInfo(child) => builder.tx_info(&child.tx_rates),
+                HwsimAttrTxInfoFlags(child) => builder.tx_info_flags(&child.tx_rate_flags),
                 _ => {
                     return Err(anyhow!(
                         "Invalid attribute message: {:?}",
-                        hwsim_attr.get_nla_type() as u32
+                        hwsim_attr.nla_type as u32
                     ))
                 }
             };
@@ -313,9 +297,9 @@
     #[test]
     fn test_attr_set_parse() {
         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
-        let hwsim_msg = HwsimMsg::parse(&packet).unwrap();
-        assert_eq!(hwsim_msg.get_hwsim_hdr().hwsim_cmd, HwsimCmd::Frame);
-        let attrs = HwsimAttrSet::parse(hwsim_msg.get_attributes()).unwrap();
+        let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
+        assert_eq!(hwsim_msg.hwsim_hdr().hwsim_cmd, HwsimCmd::Frame);
+        let attrs = HwsimAttrSet::parse(hwsim_msg.attributes()).unwrap();
 
         // Validate each attribute parsed
         assert_eq!(attrs.transmitter, MacAddress::try_from(11670786u64).ok());
@@ -336,10 +320,10 @@
     #[test]
     fn test_attr_set_attributes() {
         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
-        let hwsim_msg = HwsimMsg::parse(&packet).unwrap();
-        assert_eq!(hwsim_msg.get_hwsim_hdr().hwsim_cmd, HwsimCmd::Frame);
-        let attrs = HwsimAttrSet::parse(hwsim_msg.get_attributes()).unwrap();
-        assert_eq!(&attrs.attributes, hwsim_msg.get_attributes());
+        let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
+        assert_eq!(hwsim_msg.hwsim_hdr().hwsim_cmd, HwsimCmd::Frame);
+        let attrs = HwsimAttrSet::parse(hwsim_msg.attributes()).unwrap();
+        assert_eq!(&attrs.attributes, hwsim_msg.attributes());
     }
 
     /// Validate changing frame and transmitter during the parse.
@@ -349,12 +333,12 @@
     #[test]
     fn test_attr_set_parse_with_frame_transmitter() -> Result<(), Error> {
         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
-        let hwsim_msg = HwsimMsg::parse(&packet)?;
-        assert_eq!(hwsim_msg.get_hwsim_hdr().hwsim_cmd, HwsimCmd::Frame);
-        let attrs = HwsimAttrSet::parse(hwsim_msg.get_attributes())?;
+        let hwsim_msg = HwsimMsg::decode_full(&packet)?;
+        assert_eq!(hwsim_msg.hwsim_hdr().hwsim_cmd, HwsimCmd::Frame);
+        let attrs = HwsimAttrSet::parse(hwsim_msg.attributes())?;
         let transmitter: [u8; 6] = attrs.transmitter.context("transmitter")?.into();
         let mod_attrs = HwsimAttrSet::parse_with_frame_transmitter(
-            hwsim_msg.get_attributes(),
+            hwsim_msg.attributes(),
             attrs.frame.as_deref(),
             Some(&transmitter),
         )?;
@@ -381,8 +365,8 @@
     #[test]
     fn test_hwsim_attr_set_display() {
         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
-        let hwsim_msg = HwsimMsg::parse(&packet).unwrap();
-        let attrs = HwsimAttrSet::parse(hwsim_msg.get_attributes()).unwrap();
+        let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
+        let attrs = HwsimAttrSet::parse(hwsim_msg.attributes()).unwrap();
 
         let fmt_attrs = format!("{}", attrs);
         assert!(fmt_attrs.contains("transmitter: 02:15:b2:00:00:00"));
diff --git a/rust/daemon/src/wifi/medium.rs b/rust/daemon/src/wifi/medium.rs
index c1521f0..c54a114 100644
--- a/rust/daemon/src/wifi/medium.rs
+++ b/rust/daemon/src/wifi/medium.rs
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 use super::packets::ieee80211::MacAddress;
-use super::packets::mac80211_hwsim::{HwsimCmd, HwsimMsg, HwsimMsgBuilder, HwsimMsgHdr, NlMsgHdr};
+use super::packets::mac80211_hwsim::{HwsimCmd, HwsimMsg, HwsimMsgHdr, NlMsgHdr};
 use crate::wifi::frame::Frame;
 use crate::wifi::hwsim_attr_set::HwsimAttrSet;
 use anyhow::{anyhow, Context};
@@ -162,11 +162,11 @@
     }
 
     fn process_internal(&self, client_id: u32, packet: &Bytes) -> anyhow::Result<bool> {
-        let hwsim_msg = HwsimMsg::parse(packet)?;
+        let hwsim_msg = HwsimMsg::decode_full(packet)?;
 
         // The virtio handler only accepts HWSIM_CMD_FRAME, HWSIM_CMD_TX_INFO_FRAME and HWSIM_CMD_REPORT_PMSR
         // in https://source.corp.google.com/h/kernel/pub/scm/linux/kernel/git/torvalds/linux/+/master:drivers/net/wireless/virtual/mac80211_hwsim.c
-        match hwsim_msg.get_hwsim_hdr().hwsim_cmd {
+        match hwsim_msg.hwsim_hdr.hwsim_cmd {
             HwsimCmd::Frame => {
                 let frame = Frame::parse(&hwsim_msg)?;
                 // Incoming frame must contain transmitter, flag, cookie, and tx_info fields.
@@ -233,8 +233,8 @@
             }
             return Ok(());
         }
-        let hwsim_msg = HwsimMsg::parse(packet)?;
-        let hwsim_cmd = hwsim_msg.get_hwsim_hdr().hwsim_cmd;
+        let hwsim_msg = HwsimMsg::decode_full(packet)?;
+        let hwsim_cmd = hwsim_msg.hwsim_hdr.hwsim_cmd;
         match hwsim_cmd {
             HwsimCmd::Frame => self.send_frame_response(packet, &hwsim_msg)?,
             // TODO: Handle sending TxInfo frame for WifiService so we don't have to
@@ -281,7 +281,7 @@
     }
 
     fn send_tx_info_response(&self, packet: &Bytes, hwsim_msg: &HwsimMsg) -> anyhow::Result<()> {
-        let attrs = HwsimAttrSet::parse(hwsim_msg.get_attributes()).context("HwsimAttrSet")?;
+        let attrs = HwsimAttrSet::parse(&hwsim_msg.attributes).context("HwsimAttrSet")?;
         let hwsim_addr = attrs.transmitter.context("missing transmitter")?;
         let client_ids = self
             .stations()
@@ -440,7 +440,7 @@
     // Simulates transmission through hostapd.
     fn create_hwsim_msg(&self, frame: &Frame, dest_hwsim_addr: &MacAddress) -> Option<HwsimMsg> {
         let hwsim_msg = &frame.hwsim_msg;
-        assert_eq!(hwsim_msg.get_hwsim_hdr().hwsim_cmd, HwsimCmd::Frame);
+        assert_eq!(hwsim_msg.hwsim_hdr.hwsim_cmd, HwsimCmd::Frame);
         let attributes_result = self.create_hwsim_attr(frame, dest_hwsim_addr);
         let attributes = match attributes_result {
             Ok(attributes) => attributes,
@@ -450,20 +450,19 @@
             }
         };
 
-        let nlmsg_len = hwsim_msg.get_nl_hdr().nlmsg_len + attributes.len() as u32
-            - hwsim_msg.get_attributes().len() as u32;
-        let new_hwsim_msg = HwsimMsgBuilder {
+        let nlmsg_len = hwsim_msg.nl_hdr.nlmsg_len + attributes.len() as u32
+            - hwsim_msg.attributes.len() as u32;
+        let new_hwsim_msg = HwsimMsg {
             nl_hdr: NlMsgHdr {
                 nlmsg_len,
                 nlmsg_type: NLMSG_MIN_TYPE,
-                nlmsg_flags: hwsim_msg.get_nl_hdr().nlmsg_flags,
+                nlmsg_flags: hwsim_msg.nl_hdr.nlmsg_flags,
                 nlmsg_seq: 0,
                 nlmsg_pid: 0,
             },
-            hwsim_hdr: hwsim_msg.get_hwsim_hdr().clone(),
+            hwsim_hdr: hwsim_msg.hwsim_hdr.clone(),
             attributes,
-        }
-        .build();
+        };
         Some(new_hwsim_msg)
     }
 }
@@ -479,10 +478,10 @@
 ///
 /// Reference to ackLocalFrame() in external/qemu/android-qemu2-glue/emulation/VirtioWifiForwarder.cpp
 fn build_tx_info(hwsim_msg: &HwsimMsg) -> anyhow::Result<HwsimMsg> {
-    let attrs = HwsimAttrSet::parse(hwsim_msg.get_attributes()).context("HwsimAttrSet").unwrap();
+    let attrs = HwsimAttrSet::parse(&hwsim_msg.attributes).context("HwsimAttrSet").unwrap();
 
-    let hwsim_hdr = hwsim_msg.get_hwsim_hdr();
-    let nl_hdr = hwsim_msg.get_nl_hdr();
+    let hwsim_hdr = &hwsim_msg.hwsim_hdr;
+    let nl_hdr = &hwsim_msg.nl_hdr;
     let mut new_attr_builder = HwsimAttrSet::builder();
     const HWSIM_TX_STAT_ACK: u32 = 1 << 2;
 
@@ -496,7 +495,7 @@
     let new_attr = new_attr_builder.build().unwrap();
     let nlmsg_len =
         nl_hdr.nlmsg_len + new_attr.attributes.len() as u32 - attrs.attributes.len() as u32;
-    let new_hwsim_msg = HwsimMsgBuilder {
+    let new_hwsim_msg = HwsimMsg {
         attributes: new_attr.attributes,
         hwsim_hdr: HwsimMsgHdr {
             hwsim_cmd: HwsimCmd::TxInfoFrame,
@@ -510,21 +509,20 @@
             nlmsg_seq: 0,
             nlmsg_pid: 0,
         },
-    }
-    .build();
+    };
     Ok(new_hwsim_msg)
 }
 
 // It's used by radiotap.rs for packet capture.
 pub fn parse_hwsim_cmd(packet: &[u8]) -> anyhow::Result<HwsimCmdEnum> {
-    let hwsim_msg = HwsimMsg::parse(packet)?;
-    match hwsim_msg.get_hwsim_hdr().hwsim_cmd {
+    let hwsim_msg = HwsimMsg::decode_full(packet)?;
+    match hwsim_msg.hwsim_hdr.hwsim_cmd {
         HwsimCmd::Frame => {
             let frame = Frame::parse(&hwsim_msg)?;
             Ok(HwsimCmdEnum::Frame(Box::new(frame)))
         }
         HwsimCmd::TxInfoFrame => Ok(HwsimCmdEnum::TxInfoFrame),
-        _ => Err(anyhow!("Unknown HwsimMsg cmd={:?}", hwsim_msg.get_hwsim_hdr().hwsim_cmd)),
+        _ => Err(anyhow!("Unknown HwsimMsg cmd={:?}", hwsim_msg.hwsim_hdr.hwsim_cmd)),
     }
 }
 
@@ -598,7 +596,7 @@
     #[test]
     fn test_is_mdns_packet() {
         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame_mdns.csv");
-        let hwsim_msg = HwsimMsg::parse(&packet).unwrap();
+        let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
         let mdns_frame = Frame::parse(&hwsim_msg).unwrap();
         assert!(!mdns_frame.ieee80211.get_source().is_multicast());
         assert!(mdns_frame.ieee80211.get_destination().is_multicast());
@@ -607,8 +605,8 @@
     #[test]
     fn test_build_tx_info_reconstruct() {
         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_tx_info.csv");
-        let hwsim_msg = HwsimMsg::parse(&packet).unwrap();
-        assert_eq!(hwsim_msg.get_hwsim_hdr().hwsim_cmd, HwsimCmd::TxInfoFrame);
+        let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
+        assert_eq!(hwsim_msg.hwsim_hdr().hwsim_cmd, HwsimCmd::TxInfoFrame);
 
         let new_hwsim_msg = build_tx_info(&hwsim_msg).unwrap();
         assert_eq!(hwsim_msg, new_hwsim_msg);
@@ -617,23 +615,23 @@
     #[test]
     fn test_build_tx_info() {
         let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
-        let hwsim_msg = HwsimMsg::parse(&packet).unwrap();
+        let hwsim_msg = HwsimMsg::decode_full(&packet).unwrap();
         let hwsim_msg_tx_info = build_tx_info(&hwsim_msg).unwrap();
-        assert_eq!(hwsim_msg_tx_info.get_hwsim_hdr().hwsim_cmd, HwsimCmd::TxInfoFrame);
+        assert_eq!(hwsim_msg_tx_info.hwsim_hdr().hwsim_cmd, HwsimCmd::TxInfoFrame);
     }
 
     fn build_tx_info_and_compare(frame_bytes: &Bytes, tx_info_expected_bytes: &Bytes) {
-        let frame = HwsimMsg::parse(frame_bytes).unwrap();
+        let frame = HwsimMsg::decode_full(frame_bytes).unwrap();
         let tx_info = build_tx_info(&frame).unwrap();
 
-        let tx_info_expected = HwsimMsg::parse(tx_info_expected_bytes).unwrap();
+        let tx_info_expected = HwsimMsg::decode_full(tx_info_expected_bytes).unwrap();
 
-        assert_eq!(tx_info.get_hwsim_hdr(), tx_info_expected.get_hwsim_hdr());
-        assert_eq!(tx_info.get_nl_hdr(), tx_info_expected.get_nl_hdr());
+        assert_eq!(tx_info.hwsim_hdr(), tx_info_expected.hwsim_hdr());
+        assert_eq!(tx_info.nl_hdr(), tx_info_expected.nl_hdr());
 
-        let attrs = HwsimAttrSet::parse(tx_info.get_attributes()).context("HwsimAttrSet").unwrap();
+        let attrs = HwsimAttrSet::parse(tx_info.attributes()).context("HwsimAttrSet").unwrap();
         let attrs_expected =
-            HwsimAttrSet::parse(tx_info_expected.get_attributes()).context("HwsimAttrSet").unwrap();
+            HwsimAttrSet::parse(tx_info_expected.attributes()).context("HwsimAttrSet").unwrap();
 
         // NOTE: TX info is different and the counts are all zeros in the TX info packet generated by WifiService.
         // TODO: Confirm if the behavior is intended in WifiService.
diff --git a/rust/daemon/src/wireless/wifi.rs b/rust/daemon/src/wireless/wifi.rs
index f7f5ac0..55537e4 100644
--- a/rust/daemon/src/wireless/wifi.rs
+++ b/rust/daemon/src/wireless/wifi.rs
@@ -64,6 +64,7 @@
                         if crate::config::get_disable_wifi_p2p()
                             || !WIFI_MANAGER.medium.process(chip_id, &packet)
                         {
+                            // TODO: Replace with libslirp_send() and hostapd_send()
                             ffi_wifi::handle_wifi_request(chip_id, &packet.to_vec());
                             ffi_wifi::libslirp_main_loop_wait();
                         }
diff --git a/src/wifi/wifi_facade.cc b/src/wifi/wifi_facade.cc
index 0d47890..31c43fc 100644
--- a/src/wifi/wifi_facade.cc
+++ b/src/wifi/wifi_facade.cc
@@ -122,4 +122,24 @@
 #endif
 }
 
+void HostapdSendCxx(uint32_t chip_id, const rust::Vec<uint8_t> &packet) {
+#ifdef NETSIM_ANDROID_EMULATOR
+  // Send the packet to Hostapd.
+  struct iovec iov[1];
+  iov[0].iov_base = (void *)packet.data();
+  iov[0].iov_len = packet.size();
+  wifi_service->hostapd_send(android::base::IOVector(iov, iov + 1));
+#endif
+}
+
+void LibslirpSendCxx(uint32_t chip_id, const rust::Vec<uint8_t> &packet) {
+#ifdef NETSIM_ANDROID_EMULATOR
+  // Send the packet to libslirp.
+  struct iovec iov[1];
+  iov[0].iov_base = (void *)packet.data();
+  iov[0].iov_len = packet.size();
+  wifi_service->libslirp_send(android::base::IOVector(iov, iov + 1));
+#endif
+}
+
 }  // namespace netsim::wifi
diff --git a/src/wifi/wifi_packet_hub.h b/src/wifi/wifi_packet_hub.h
index a133594..a583d6e 100644
--- a/src/wifi/wifi_packet_hub.h
+++ b/src/wifi/wifi_packet_hub.h
@@ -31,4 +31,8 @@
 
 void HandleWifiRequestCxx(uint32_t chip_id, const rust::Vec<uint8_t> &packet);
 
+void HostapdSendCxx(uint32_t chip_id, const rust::Vec<uint8_t> &packet);
+
+void LibslirpSendCxx(uint32_t chip_id, const rust::Vec<uint8_t> &packet);
+
 }  // namespace netsim::wifi