aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-01-08 21:48:48 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-01-08 21:48:48 +0000
commita6ed50e171e39d7d145dce75866f51d63b4aa41d (patch)
treef350f8d408ab6b05bbf285f1469c79d27d444080
parentf33f179ba09b0c057d9e9b63c0060edc7aa46acb (diff)
parent2fc6f103439e3d1a29512a094f3dfc1686749279 (diff)
downloadnetsim-a6ed50e171e39d7d145dce75866f51d63b4aa41d.tar.gz
Snap for 11286485 from 2fc6f103439e3d1a29512a094f3dfc1686749279 to emu-34-release
Change-Id: I75a063c29dd571770f4de1147ce4dd7c7e384d90
-rw-r--r--Android.bp25
-rw-r--r--cmake/netsim_dependencies.cmake4
-rw-r--r--pdl/mac80211_hwsim.pdl2
-rw-r--r--rust/cli/Cargo.toml2
-rw-r--r--rust/daemon/Cargo.toml2
-rw-r--r--rust/daemon/src/echip/mod.rs4
-rw-r--r--rust/daemon/src/echip/packet.rs14
-rw-r--r--rust/daemon/src/echip/wifi.rs18
-rw-r--r--rust/daemon/src/rust_main.rs94
-rw-r--r--rust/daemon/src/session.rs247
-rw-r--r--rust/daemon/src/version.rs2
-rw-r--r--rust/daemon/src/wifi/frame.rs194
-rw-r--r--rust/daemon/src/wifi/hwsim_attr_set.rs309
-rw-r--r--rust/daemon/src/wifi/ieee80211.rs58
-rw-r--r--rust/daemon/src/wifi/medium.rs272
-rw-r--r--rust/daemon/src/wifi/mod.rs1
-rw-r--r--rust/daemon/src/wifi/test_packets/hwsim_cmd_frame.csv1
-rw-r--r--rust/daemon/src/wifi/test_packets/hwsim_cmd_frame2.csv1
-rw-r--r--rust/daemon/src/wifi/test_packets/hwsim_cmd_frame_mdns.csv1
-rw-r--r--rust/daemon/src/wifi/test_packets/hwsim_cmd_frame_no_cookie.csv1
-rw-r--r--rust/daemon/src/wifi/test_packets/hwsim_cmd_tx_info.csv1
-rw-r--r--rust/frontend/Cargo.toml23
-rw-r--r--rust/frontend/src/netsim_test_client.rs30
-rw-r--r--rust/frontend/src/netsim_test_server.rs117
-rw-r--r--rust/proto/src/frontend.rs219
-rw-r--r--rust/proto/src/frontend_grpc.rs558
-rw-r--r--rust/proto/src/lib.rs5
-rwxr-xr-xscripts/build_tools.py7
-rwxr-xr-xscripts/proto_update.sh7
-rw-r--r--scripts/utils.py8
30 files changed, 1936 insertions, 291 deletions
diff --git a/Android.bp b/Android.bp
index 512e8d2..8d0f679 100644
--- a/Android.bp
+++ b/Android.bp
@@ -302,10 +302,12 @@ cc_test_host {
rust_library_host {
name: "libnetsim_proto",
+ features: ["cuttlefish"],
crate_name: "netsim_proto",
srcs: ["rust/proto/src/lib.rs"],
rustlibs: [
"libprotobuf",
+ "libgrpcio",
],
}
@@ -404,3 +406,26 @@ rust_binary_host {
"libnetsim_cli",
],
}
+
+rust_binary_host {
+ name: "netsim_test_client",
+ srcs: ["rust/frontend/src/netsim_test_client.rs"],
+ rustlibs: [
+ "libgrpcio",
+ "libnetsim_proto",
+ "libprotobuf",
+ "libnetsim_common",
+ ],
+}
+
+rust_binary_host {
+ name: "netsim_test_server",
+ srcs: ["rust/frontend/src/netsim_test_server.rs"],
+ rustlibs: [
+ "libgrpcio",
+ "libnetsim_proto",
+ "libprotobuf",
+ "libnetsim_common",
+ "libfutures",
+ ],
+}
diff --git a/cmake/netsim_dependencies.cmake b/cmake/netsim_dependencies.cmake
index 658ece9..8f063f7 100644
--- a/cmake/netsim_dependencies.cmake
+++ b/cmake/netsim_dependencies.cmake
@@ -1,5 +1,5 @@
set(BLUETOOTH_EMULATION True)
-set(AOSP ${CMAKE_CURRENT_LIST_DIR}/../../..)
+get_filename_component(AOSP "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE)
set(EXTERNAL ${AOSP}/external)
set(EXTERNAL_QEMU ${EXTERNAL}/qemu)
set(ANDROID_QEMU2_TOP_DIR ${EXTERNAL_QEMU})
@@ -34,7 +34,6 @@ set(_gRPC_RE2_INCLUDE_DIR "${EXTERNAL_QEMU}/android/third_party/re2")
set(_gRPC_RE2_LIBRARIES re2)
set(NETSIM_EXT TRUE)
-
# Let's bin place everything in the root, with the shared libs in the right
# place
set(DBG_INFO ${CMAKE_BINARY_DIR}/build/debug_info)
@@ -50,7 +49,6 @@ else()
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/distribution/emulator)
endif()
-
# First make the protobuf and dependencies available to gRPC
add_subdirectory(${EXTERNAL}/qemu/android/third_party/protobuf protobuf)
diff --git a/pdl/mac80211_hwsim.pdl b/pdl/mac80211_hwsim.pdl
index dce9518..5ca3c70 100644
--- a/pdl/mac80211_hwsim.pdl
+++ b/pdl/mac80211_hwsim.pdl
@@ -242,7 +242,7 @@ struct HwsimMsgHdr {
reserved: 16,
}
-struct HwsimMsg {
+packet HwsimMsg {
nl_hdr: NlMsgHdr,
hwsim_hdr: HwsimMsgHdr,
// user header
diff --git a/rust/cli/Cargo.toml b/rust/cli/Cargo.toml
index 3df2f83..7f25581 100644
--- a/rust/cli/Cargo.toml
+++ b/rust/cli/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "netsim-cli"
-version = "0.2.3"
+version = "0.2.6"
edition = "2021"
build = "build.rs"
diff --git a/rust/daemon/Cargo.toml b/rust/daemon/Cargo.toml
index 6b970dd..a309677 100644
--- a/rust/daemon/Cargo.toml
+++ b/rust/daemon/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "netsim-daemon"
-version = "0.2.3"
+version = "0.2.6"
edition = "2021"
build = "build.rs"
diff --git a/rust/daemon/src/echip/mod.rs b/rust/daemon/src/echip/mod.rs
index 010c9e4..5e8712e 100644
--- a/rust/daemon/src/echip/mod.rs
+++ b/rust/daemon/src/echip/mod.rs
@@ -23,4 +23,6 @@ pub use crate::echip::emulated_chip::CreateParam;
pub use crate::echip::emulated_chip::EmulatedChip;
pub use crate::echip::emulated_chip::SharedEmulatedChip;
pub use crate::echip::emulated_chip::{get, new, remove};
-pub use crate::echip::packet::{handle_request, handle_request_cxx, handle_response};
+pub use crate::echip::packet::{
+ handle_request, handle_request_cxx, handle_response, hwsim_cmd_response,
+};
diff --git a/rust/daemon/src/echip/packet.rs b/rust/daemon/src/echip/packet.rs
index 8140594..d92888a 100644
--- a/rust/daemon/src/echip/packet.rs
+++ b/rust/daemon/src/echip/packet.rs
@@ -116,6 +116,20 @@ pub fn handle_response(chip_id: ChipIdentifier, packet: &cxx::CxxVector<u8>, pac
};
}
+// Send HwsimCmd packets to guest OS.
+pub fn hwsim_cmd_response(client_id: u32, packet: &[u8]) {
+ let mut senders = SENDERS.lock();
+ if let Some(responder) = senders.get(&client_id) {
+ let packet_type = PacketType::HCI_PACKET_UNSPECIFIED.value() as u8;
+ if responder.send(ResponsePacket { packet: packet.to_owned(), packet_type }).is_err() {
+ warn!("send failed for client: {client_id}");
+ senders.remove(&client_id); // Remove from the map using the value itself
+ }
+ } else {
+ warn!("unknown client: {client_id}");
+ }
+}
+
/// Handle requests from transports.
pub fn handle_request(chip_id: ChipIdentifier, packet: &mut Vec<u8>, packet_type: u8) {
captures_handler::handle_packet_request(chip_id, packet, packet_type.into());
diff --git a/rust/daemon/src/echip/wifi.rs b/rust/daemon/src/echip/wifi.rs
index 2dba81a..101f259 100644
--- a/rust/daemon/src/echip/wifi.rs
+++ b/rust/daemon/src/echip/wifi.rs
@@ -13,9 +13,10 @@
// limitations under the License.
use crate::devices::chip::ChipIdentifier;
-use crate::echip::{EmulatedChip, SharedEmulatedChip};
+use crate::echip::{packet::hwsim_cmd_response, EmulatedChip, SharedEmulatedChip};
use crate::ffi::ffi_wifi;
-use crate::wifi::medium;
+use crate::wifi::medium::Medium;
+use lazy_static::lazy_static;
use log::info;
use netsim_proto::common::ChipKind as ProtoChipKind;
use netsim_proto::config::WiFi as WiFiConfig;
@@ -34,12 +35,16 @@ pub struct Wifi {
chip_id: ChipIdentifier,
}
+// Allocator for chip identifiers.
+lazy_static! {
+ static ref MEDIUM: Mutex<Medium> = Mutex::new(Medium::new(hwsim_cmd_response));
+}
+
impl EmulatedChip for Wifi {
fn handle_request(&self, packet: &[u8]) {
- if crate::config::get_dev() {
- let _ = medium::parse_hwsim_cmd(packet);
+ if !MEDIUM.lock().expect("Lock failed").process(self.chip_id, packet) {
+ ffi_wifi::handle_wifi_request(self.chip_id, &packet.to_vec());
}
- ffi_wifi::handle_wifi_request(self.chip_id, &packet.to_vec());
}
fn reset(&mut self) {
@@ -90,9 +95,6 @@ pub fn new(_params: &CreateParams, chip_id: ChipIdentifier) -> SharedEmulatedChi
/// Starts the WiFi service.
pub fn wifi_start(config: &MessageField<WiFiConfig>) {
- if crate::config::get_dev() {
- medium::test_parse_hwsim_cmd();
- }
let proto_bytes = config.as_ref().unwrap_or_default().write_to_bytes().unwrap();
ffi_wifi::wifi_start(&proto_bytes);
}
diff --git a/rust/daemon/src/rust_main.rs b/rust/daemon/src/rust_main.rs
index a0a8aa1..ce66d1b 100644
--- a/rust/daemon/src/rust_main.rs
+++ b/rust/daemon/src/rust_main.rs
@@ -34,7 +34,7 @@ use crate::ffi::ffi_util;
use crate::service::{new_test_beacon, Service, ServiceParams};
#[cfg(feature = "cuttlefish")]
use netsim_common::util::os_utils::get_server_address;
-use netsim_proto::config::{Bluetooth as BluetoothConfig, Config};
+use netsim_proto::config::{Bluetooth as BluetoothConfig, Capture, Config};
use std::env;
use std::ffi::{c_char, c_int};
use std::sync::mpsc::Receiver;
@@ -155,18 +155,63 @@ fn main_loop(events_rx: Receiver<Event>) {
}
}
-fn run_netsimd_primary(args: NetsimdArgs) {
+// Disambiguate config and command line args and store merged setting in config
+fn disambiguate_args(args: &mut NetsimdArgs, config: &mut Config) {
+ // Command line override config file arguments
+
+ // Currently capture cannot be specified off explicitly with command line.
+ // Enable capture if enabled by command line arg
+ if args.pcap {
+ match config.capture.as_mut() {
+ Some(capture) => {
+ capture.enabled = Some(true);
+ }
+ None => {
+ let mut capture = Capture::new();
+ capture.enabled = Some(true);
+ config.capture = Some(capture).into();
+ }
+ }
+ }
+
+ // Ensure Bluetooth config is initialized
+ let bt_config = match config.bluetooth.as_mut() {
+ Some(existing_bt_config) => existing_bt_config,
+ None => {
+ config.bluetooth = Some(BluetoothConfig::new()).into();
+ config.bluetooth.as_mut().unwrap()
+ }
+ };
+
+ // Set disable_address_reuse as needed
+ if args.disable_address_reuse {
+ bt_config.disable_address_reuse = Some(true);
+ }
+
+ // Determine test beacons configuration, default true for cuttlefish
+ // TODO: remove default for cuttlefish by adding flag to tests
+ bt_config.test_beacons = match (args.test_beacons, args.no_test_beacons) {
+ (true, false) => Some(true),
+ (false, true) => Some(false),
+ (false, false) => match bt_config.test_beacons {
+ Some(test_beacons) => Some(test_beacons),
+ None => Some(cfg!(feature = "cuttlefish")),
+ },
+ (true, true) => panic!("unexpected flag combination"),
+ };
+}
+
+fn run_netsimd_primary(mut args: NetsimdArgs) {
info!("Netsim Version: {}", get_version());
- let fd_startup_str = args.fd_startup_str.unwrap_or_default();
+ let fd_startup_str = args.fd_startup_str.clone().unwrap_or_default();
let instance_num = get_instance(args.instance);
let hci_port: u16 =
get_hci_port(args.hci_port.unwrap_or_default(), instance_num - 1).try_into().unwrap();
#[cfg(feature = "cuttlefish")]
if fd_startup_str.is_empty() {
- warn!("Failed to start netsim daemon because fd startup flag `-s` is empty");
- return;
+ warn!("Warning: netsimd startup flag -s is empty, waiting for gRPC connections.");
}
if ffi_util::is_netsimd_alive(instance_num) {
@@ -174,11 +219,11 @@ fn run_netsimd_primary(args: NetsimdArgs) {
return;
}
+ // Load config file
let mut config = Config::new();
- if let Some(filename) = args.config {
- match config_file::new_from_file(&filename) {
+ if let Some(ref filename) = args.config {
+ match config_file::new_from_file(filename) {
Ok(config_from_file) => {
- info!("Using config in {}", config);
config = config_from_file;
}
Err(e) => {
@@ -186,12 +231,17 @@ fn run_netsimd_primary(args: NetsimdArgs) {
}
}
}
+ // Disambiguate conflicts between cmdline args and config file
+ disambiguate_args(&mut args, &mut config);
+
+ // Print config file settings
+ info!("{:#?}", config);
let service_params = ServiceParams::new(
fd_startup_str,
args.no_cli_ui,
args.no_web_ui,
- config.capture.enabled == Some(true) || args.pcap,
+ config.capture.enabled.unwrap_or_default(),
hci_port,
instance_num,
args.dev,
@@ -220,34 +270,12 @@ fn run_netsimd_primary(args: NetsimdArgs) {
spawn_shutdown_publisher(device_events_rx);
}
- // Command line over-rides config file
- if args.disable_address_reuse {
- match config.bluetooth.as_mut() {
- Some(bt_config) => {
- bt_config.disable_address_reuse = Some(true);
- }
- None => {
- let mut bt_config = BluetoothConfig::new();
- bt_config.disable_address_reuse = Some(true);
- config.bluetooth = Some(bt_config).into();
- }
- }
- }
-
// Start radio facades
echip::bluetooth::bluetooth_start(&config.bluetooth, instance_num);
echip::wifi::wifi_start(&config.wifi);
- // Maybe create test beacons, default true for cuttlefish
- // TODO: remove default for cuttlefish by adding flag to tests
- if config.bluetooth.test_beacons == Some(true)
- || match (args.test_beacons, args.no_test_beacons) {
- (true, false) => true,
- (false, true) => false,
- (false, false) => cfg!(feature = "cuttlefish"),
- (true, true) => panic!("unexpected flag combination"),
- }
- {
+ // Create test beacons if required
+ if config.bluetooth.test_beacons == Some(true) {
new_test_beacon(1, 1000);
new_test_beacon(2, 1000);
}
diff --git a/rust/daemon/src/session.rs b/rust/daemon/src/session.rs
index ac87adc..fbb87b7 100644
--- a/rust/daemon/src/session.rs
+++ b/rust/daemon/src/session.rs
@@ -46,16 +46,21 @@ struct SessionInfo {
stats_proto: NetsimStats,
current_device_count: i32,
session_start: Instant,
+ write_json: bool,
}
impl Session {
pub fn new() -> Self {
+ Self::new_internal(true)
+ }
+ fn new_internal(write_json: bool) -> Self {
Session {
handle: None,
info: Arc::new(RwLock::new(SessionInfo {
stats_proto: NetsimStats { version: Some(get_version()), ..Default::default() },
current_device_count: 0,
session_start: Instant::now(),
+ write_json,
})),
}
}
@@ -65,7 +70,8 @@ impl Session {
// Starts the session monitor thread to handle events and
// write session stats to json file on event and periodically.
pub fn start(&mut self, events_rx: Receiver<Event>) -> &mut Self {
- let info = self.info.clone();
+ let info = Arc::clone(&self.info);
+
// Start up session monitor thread
self.handle = Some(
Builder::new()
@@ -73,8 +79,6 @@ impl Session {
.spawn(move || {
let mut next_instant = Instant::now() + WRITE_INTERVAL;
loop {
- // Hold the write lock for the duration of this loop iteration
- let mut lock = info.write().expect("Could not acquire session lock");
let mut write_stats = true;
let this_instant = Instant::now();
let timeout = if next_instant > this_instant {
@@ -82,7 +86,11 @@ impl Session {
} else {
Duration::ZERO
};
- match events_rx.recv_timeout(timeout) {
+ let next_event = events_rx.recv_timeout(timeout);
+
+ // Hold the write lock for the duration of this loop iteration
+ let mut lock = info.write().expect("Could not acquire session lock");
+ match next_event {
Ok(Event::ShutDown(ShutDown { reason })) => {
// Shutting down, save the session duration and exit
update_session_duration(&mut lock);
@@ -134,9 +142,11 @@ impl Session {
// End of event match - write current stats to json
if write_stats {
update_session_duration(&mut lock);
- let current_stats = get_current_stats(lock.stats_proto.clone());
- if let Err(err) = write_stats_to_json(current_stats) {
- error!("Failed to write stats to json: {err:?}");
+ if lock.write_json {
+ let current_stats = get_current_stats(lock.stats_proto.clone());
+ if let Err(err) = write_stats_to_json(current_stats) {
+ error!("Failed to write stats to json: {err:?}");
+ }
}
next_instant = Instant::now() + WRITE_INTERVAL;
}
@@ -155,10 +165,14 @@ impl Session {
if !self.handle.as_ref().expect("no session monitor").is_finished() {
info!("session monitor active, waiting...");
}
+
// Synchronize on session monitor thread
self.handle.take().map(JoinHandle::join);
+
let lock = self.info.read().expect("Could not acquire session lock");
- write_stats_to_json(lock.stats_proto.clone())?;
+ if lock.write_json {
+ write_stats_to_json(lock.stats_proto.clone())?;
+ }
Ok(())
}
}
@@ -184,3 +198,220 @@ fn write_stats_to_json(stats_proto: NetsimStats) -> anyhow::Result<()> {
file.flush()?;
Ok(())
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::events;
+ use crate::events::{
+ ChipAdded, ChipRemoved, DeviceAdded, DeviceRemoved, Event, Events, ShutDown,
+ };
+ use netsim_proto::stats::NetsimRadioStats;
+ use std::sync::Mutex;
+
+ #[test]
+ fn test_new() {
+ let session: Session = Session::new();
+ assert!(session.handle.is_none());
+ let lock = session.info.read().expect("Could not acquire session lock");
+ assert_eq!(lock.current_device_count, 0);
+ assert!(matches!(
+ lock.stats_proto,
+ NetsimStats { version: Some(_), duration_secs: None, .. }
+ ));
+ assert_eq!(lock.stats_proto.version.clone().unwrap(), get_version().clone());
+ assert_eq!(lock.stats_proto.radio_stats.len(), 0);
+ }
+
+ fn setup_session_start_test() -> (Session, Arc<Mutex<Events>>) {
+ let mut session = Session::new_internal(false);
+ let mut events = events::test::new();
+ let events_rx = events::test::subscribe(&mut events);
+ session.start(events_rx);
+ (session, events)
+ }
+
+ fn get_stats_proto(session: &Session) -> NetsimStats {
+ session.info.read().expect("Could not acquire session lock").stats_proto.clone()
+ }
+
+ #[test]
+ fn test_start_and_shutdown() {
+ let (mut session, mut events) = setup_session_start_test();
+
+ // we want to be able to check the session time gets incremented
+ std::thread::sleep(std::time::Duration::from_secs(1));
+
+ // publish the shutdown afterwards to cause the separate thread to stop
+ events::test::publish(
+ &mut events,
+ Event::ShutDown(ShutDown { reason: "Stop the session".to_string() }),
+ );
+
+ // join the handle
+ session.handle.take().map(JoinHandle::join);
+
+ let stats_proto = get_stats_proto(&session);
+
+ // check device counts are missing if no device add/remove events occurred
+ assert!(stats_proto.device_count.is_none());
+
+ assert!(stats_proto.peak_concurrent_devices.is_none());
+
+ // check the session time is > 0
+ assert!(stats_proto.duration_secs.unwrap() > 0u64);
+ }
+
+ #[test]
+ fn test_start_and_stop() {
+ let (session, mut events) = setup_session_start_test();
+
+ // we want to be able to check the session time gets incremented
+ std::thread::sleep(std::time::Duration::from_secs(1));
+
+ // publish the shutdown which is required when using `session.stop()`
+ events::test::publish(
+ &mut events,
+ Event::ShutDown(ShutDown { reason: "Stop the session".to_string() }),
+ );
+
+ // should not panic or deadlock
+ session.stop().unwrap();
+ }
+
+ #[test]
+ fn test_start_and_device_add() {
+ let (mut session, mut events) = setup_session_start_test();
+
+ // we want to be able to check the session time gets incremented
+ std::thread::sleep(std::time::Duration::from_secs(1));
+
+ events::test::publish(
+ &mut events,
+ Event::DeviceAdded(DeviceAdded { builtin: false, ..Default::default() }),
+ );
+
+ // publish the shutdown afterwards to cause the separate thread to stop
+ events::test::publish(
+ &mut events,
+ Event::ShutDown(ShutDown { reason: "Stop the session".to_string() }),
+ );
+
+ // join the handle
+ session.handle.take().map(JoinHandle::join);
+
+ // check device counts were incremented
+ assert_eq!(
+ session.info.read().expect("Could not acquire session lock").current_device_count,
+ 1i32
+ );
+ let stats_proto = get_stats_proto(&session);
+
+ assert_eq!(stats_proto.device_count.unwrap(), 1i32);
+ assert_eq!(stats_proto.peak_concurrent_devices.unwrap(), 1i32);
+ // check the session time is > 0
+ assert!(stats_proto.duration_secs.unwrap() > 0u64);
+ }
+
+ #[test]
+ fn test_start_and_device_add_and_remove() {
+ let (mut session, mut events) = setup_session_start_test();
+
+ // we want to be able to check the session time gets incremented
+ std::thread::sleep(std::time::Duration::from_secs(1));
+
+ events::test::publish(
+ &mut events,
+ Event::DeviceAdded(DeviceAdded { builtin: false, id: 1, ..Default::default() }),
+ );
+
+ events::test::publish(
+ &mut events,
+ Event::DeviceRemoved(DeviceRemoved { builtin: false, id: 1, ..Default::default() }),
+ );
+
+ events::test::publish(
+ &mut events,
+ Event::DeviceAdded(DeviceAdded { builtin: false, id: 2, ..Default::default() }),
+ );
+
+ events::test::publish(
+ &mut events,
+ Event::DeviceRemoved(DeviceRemoved { builtin: false, id: 2, ..Default::default() }),
+ );
+
+ // publish the shutdown afterwards to cause the separate thread to stop
+ events::test::publish(
+ &mut events,
+ Event::ShutDown(ShutDown { reason: "Stop the session".to_string() }),
+ );
+
+ // join the handle
+ session.handle.take().map(JoinHandle::join);
+
+ // check the different device counts were incremented as expected
+ assert_eq!(
+ session.info.read().expect("Could not acquire session lock").current_device_count,
+ 0i32
+ );
+ let stats_proto = get_stats_proto(&session);
+ assert_eq!(stats_proto.device_count.unwrap(), 2i32);
+ assert_eq!(stats_proto.peak_concurrent_devices.unwrap(), 1i32);
+
+ // check the session time is > 0
+ assert!(stats_proto.duration_secs.unwrap() > 0u64);
+ }
+
+ #[test]
+ fn test_start_and_chip_add_and_remove() {
+ let (mut session, mut events) = setup_session_start_test();
+
+ // we want to be able to check the session time gets incremented
+ std::thread::sleep(std::time::Duration::from_secs(1));
+
+ events::test::publish(
+ &mut events,
+ Event::ChipAdded(ChipAdded { builtin: false, chip_id: 0, ..Default::default() }),
+ );
+
+ std::thread::sleep(std::time::Duration::from_secs(1));
+
+ // no radio stats until after we remove the chip
+ assert_eq!(get_stats_proto(&session).radio_stats.len(), 0usize);
+
+ events::test::publish(
+ &mut events,
+ Event::ChipRemoved(ChipRemoved {
+ chip_id: 0,
+ radio_stats: vec![NetsimRadioStats { ..Default::default() }],
+ ..Default::default()
+ }),
+ );
+
+ // publish the shutdown afterwards to cause the separate thread to stop
+ events::test::publish(
+ &mut events,
+ Event::ShutDown(ShutDown { reason: "Stop the session".to_string() }),
+ );
+
+ // join the handle
+ session.handle.take().map(JoinHandle::join);
+
+ // check devices were not incremented (here we only added and removed the chip)
+ assert_eq!(
+ session.info.read().expect("Could not acquire session lock").current_device_count,
+ 0i32
+ );
+
+ let stats_proto = get_stats_proto(&session);
+ assert_eq!(stats_proto.radio_stats.len(), 1usize);
+
+ // these will still be none since no device level events were processed
+ assert!(stats_proto.device_count.is_none());
+
+ assert!(stats_proto.peak_concurrent_devices.is_none());
+
+ // check the session time is > 0
+ assert!(stats_proto.duration_secs.unwrap() > 0u64);
+ }
+}
diff --git a/rust/daemon/src/version.rs b/rust/daemon/src/version.rs
index 2a0cbc9..d296da1 100644
--- a/rust/daemon/src/version.rs
+++ b/rust/daemon/src/version.rs
@@ -14,7 +14,7 @@
/// Version library.
-pub const VERSION: &str = "0.2.3";
+pub const VERSION: &str = "0.2.6";
pub fn get_version() -> String {
VERSION.to_owned()
diff --git a/rust/daemon/src/wifi/frame.rs b/rust/daemon/src/wifi/frame.rs
index 4b8f462..e2e6bca 100644
--- a/rust/daemon/src/wifi/frame.rs
+++ b/rust/daemon/src/wifi/frame.rs
@@ -12,175 +12,59 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use super::ieee80211::Ieee80211;
-use super::packets::mac80211_hwsim::HwsimAttrChild::*;
-use super::packets::mac80211_hwsim::{HwsimAttr, HwsimMsg, HwsimMsgHdr, TxRate, TxRateFlag};
-use super::packets::netlink::{NlAttrHdr, NlMsgHdr};
+use super::ieee80211::{Ieee80211, MacAddress};
+use super::packets::mac80211_hwsim::{
+ HwsimAttr, HwsimCmd, HwsimMsg, HwsimMsgHdr, TxRate, TxRateFlag,
+};
+use crate::wifi::hwsim_attr_set::HwsimAttrSet;
use anyhow::{anyhow, Context};
use log::{info, warn};
-use std::mem;
-// Decode the hwsim Frame.
-//
-// HWSIM_CMD_FRAME is used to send/receive a broadcasted frame from/to
-// kernel/user space, uses these attributes:
-//
-// HWSIM_ATTR_ADDR_TRANSMITTER,
-// HWSIM_ATTR_ADDR_RECEIVER,
-// HWSIM_ATTR_FRAME,
-// HWSIM_ATTR_FLAGS,
-// HWSIM_ATTR_RX_RATE,
-// HWSIM_ATTR_SIGNAL,
-// HWSIM_ATTR_COOKIE,
-// HWSIM_ATTR_FREQ (optional)
-// HWSIM_ATTR_TX_INFO (new use)
-// HWSIM_ATTR_TX_INFO_FLAGS (new use)
-
-const NLA_ALIGNTO: usize = 4;
-
-fn nla_align(len: usize) -> usize {
- len.wrapping_add(NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)
-}
-
-#[derive(Default)]
-struct FrameBuilder {
- transmitter: Option<[u8; 6]>,
- receiver: Option<[u8; 6]>,
- data: Option<Vec<u8>>,
- flags: Option<u32>,
- rx_rate_idx: Option<u32>,
- signal: Option<u32>,
- cookie: Option<u64>,
- freq: Option<u32>,
- tx_rates: Option<Vec<TxRate>>,
- tx_rate_flags: Option<Vec<TxRateFlag>>,
-}
+/// Parser for the hwsim Frame command (HWSIM_CMD_FRAME).
+///
+/// The Frame command is sent by the kernel's mac80211_hwsim subsystem
+/// and contains the IEEE 802.11 frame along with hwsim attributes.
+///
+/// This module parses the required and optional hwsim attributes and
+/// returns errors if any required attributes are missing.
+// The Frame struct contains parsed attributes along with the raw and
+// parsed 802.11 frame in `data` and `ieee80211.`
#[derive(Debug)]
pub struct Frame {
- transmitter: Option<[u8; 6]>,
- receiver: Option<[u8; 6]>,
- pub data: Vec<u8>,
- pub ieee80211_hdr: Option<Ieee80211>,
- pub flags: Option<u32>,
- rx_rate_idx: Option<u32>,
+ pub transmitter: MacAddress,
+ pub flags: u32,
+ pub tx_info: Vec<TxRate>,
+ pub cookie: u64,
pub signal: Option<u32>,
- cookie: Option<u64>,
pub freq: Option<u32>,
- tx_rates: Option<Vec<TxRate>>,
- tx_rate_flags: Option<Vec<TxRateFlag>>,
-}
-
-fn anymsg(attr: &str) -> anyhow::Error {
- anyhow!("hwsim Frame missing {} attribute", attr)
-}
-
-impl FrameBuilder {
- fn transmitter(&mut self, transmitter: &[u8; 6]) -> &mut Self {
- self.transmitter = Some(*transmitter);
- self
- }
-
- fn receiver(&mut self, receiver: &[u8; 6]) -> &mut Self {
- self.receiver = Some(*receiver);
- self
- }
-
- fn frame(&mut self, data: &[u8]) -> &mut Self {
- self.data = Some(data.to_vec());
- self
- }
-
- fn flags(&mut self, flags: u32) -> &mut Self {
- self.flags = Some(flags);
- self
- }
-
- fn rx_rate(&mut self, rx_rate_idx: u32) -> &mut Self {
- self.rx_rate_idx = Some(rx_rate_idx);
- self
- }
-
- fn signal(&mut self, signal: u32) -> &mut Self {
- self.signal = Some(signal);
- self
- }
-
- fn cookie(&mut self, cookie: u64) -> &mut Self {
- self.cookie = Some(cookie);
- self
- }
-
- fn freq(&mut self, freq: u32) -> &mut Self {
- self.freq = Some(freq);
- self
- }
-
- fn tx_rates(&mut self, tx_rates: &[TxRate]) -> &mut Self {
- self.tx_rates = Some(tx_rates.to_vec());
- self
- }
-
- fn tx_rate_flags(&mut self, tx_rate_flags: &[TxRateFlag]) -> &mut Self {
- self.tx_rate_flags = Some(tx_rate_flags.to_vec());
- self
- }
-
- fn build(mut self) -> anyhow::Result<Frame> {
- let data = self.data.ok_or(anymsg("frame"))?;
- let ieee80211_hdr = Ieee80211::parse(&data).ok();
- Ok(Frame {
- transmitter: self.transmitter,
- receiver: self.receiver,
- cookie: self.cookie,
- flags: self.flags,
- rx_rate_idx: self.rx_rate_idx,
- signal: self.signal,
- data,
- ieee80211_hdr,
- freq: self.freq,
- tx_rates: self.tx_rates,
- tx_rate_flags: self.tx_rate_flags,
- })
- }
+ pub data: Vec<u8>,
+ pub ieee80211: Ieee80211,
}
impl Frame {
- fn builder() -> FrameBuilder {
- FrameBuilder::default()
- }
-
// Builds and validates the Frame from the attributes in the
// packet. Called when a hwsim packet with HwsimCmd::Frame is
// found.
- pub fn new(attributes: &[u8]) -> anyhow::Result<Frame> {
- let mut index: usize = 0;
- let mut builder = Frame::builder();
- while (index < attributes.len()) {
- // Parse a generic netlink attribute to get the size
- let nla = NlAttrHdr::parse(&attributes[index..index + 4]).unwrap();
- let nla_len = nla.nla_len as usize;
- let hwsim_attr = HwsimAttr::parse(&attributes[index..index + nla_len])?;
- match hwsim_attr.specialize() {
- HwsimAttrAddrTransmitter(child) => builder.transmitter(child.get_address()),
- HwsimAttrAddrReceiver(child) => builder.receiver(child.get_address()),
- HwsimAttrFrame(child) => builder.frame(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_rates(child.get_tx_rates()),
- HwsimAttrTxInfoFlags(child) => builder.tx_rate_flags(child.get_tx_rate_flags()),
- _ => {
- return Err(anyhow!(
- "Invalid attribute in frame: {:?}",
- hwsim_attr.get_nla_type() as u32
- ))
- }
- };
- index += nla_align(nla_len);
+ 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) {
+ panic!("Invalid hwsim_cmd");
}
- builder.build()
+ let attrs = HwsimAttrSet::parse(msg.get_attributes()).context("HwsimAttrSet")?;
+ let frame = attrs.frame.clone().context("Frame")?;
+ let ieee80211 = Ieee80211::parse(&frame).context("Ieee80211")?;
+ // Required attributes are unwrapped and return an error if
+ // they are not present.
+ Ok(Frame {
+ transmitter: attrs.transmitter.context("transmitter")?,
+ flags: attrs.flags.context("flags")?,
+ tx_info: attrs.tx_info.clone().context("tx_info")?,
+ cookie: attrs.cookie.context("cookie")?,
+ signal: attrs.signal,
+ freq: attrs.freq,
+ data: frame,
+ ieee80211,
+ })
}
}
diff --git a/rust/daemon/src/wifi/hwsim_attr_set.rs b/rust/daemon/src/wifi/hwsim_attr_set.rs
new file mode 100644
index 0000000..e5bff25
--- /dev/null
+++ b/rust/daemon/src/wifi/hwsim_attr_set.rs
@@ -0,0 +1,309 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use super::ieee80211::MacAddress;
+use super::packets::mac80211_hwsim::{
+ self, HwsimAttr, HwsimAttrChild::*, HwsimCmd, HwsimMsg, HwsimMsgHdr, TxRate, TxRateFlag,
+};
+use super::packets::netlink::{NlAttrHdr, NlMsgHdr};
+use anyhow::{anyhow, Context};
+use log::{info, warn};
+use pdl_runtime::Packet;
+
+/// Parse or Build the Hwsim attributes into a set.
+///
+/// Hwsim attributes are used to exchange data between kernel's
+/// mac80211_hwsim subsystem and a user space process and include:
+///
+/// HWSIM_ATTR_ADDR_TRANSMITTER,
+/// HWSIM_ATTR_ADDR_RECEIVER,
+/// HWSIM_ATTR_FRAME,
+/// HWSIM_ATTR_FLAGS,
+/// HWSIM_ATTR_RX_RATE,
+/// HWSIM_ATTR_SIGNAL,
+/// HWSIM_ATTR_COOKIE,
+/// HWSIM_ATTR_FREQ (optional)
+/// HWSIM_ATTR_TX_INFO (new use)
+/// HWSIM_ATTR_TX_INFO_FLAGS (new use)
+
+/// Aligns a length to the specified alignment boundary (`NLA_ALIGNTO`).
+///
+/// # Arguments
+///
+/// * `array_length`: The length in bytes to be aligned.
+///
+/// # Returns
+///
+/// * The aligned length, which is a multiple of `NLA_ALIGNTO`.
+///
+fn nla_align(array_length: usize) -> usize {
+ const NLA_ALIGNTO: usize = 4;
+ array_length.wrapping_add(NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)
+}
+
+#[derive(Default)]
+pub struct HwsimAttrSetBuilder {
+ transmitter: Option<MacAddress>,
+ receiver: Option<MacAddress>,
+ frame: Option<Vec<u8>>,
+ flags: Option<u32>,
+ rx_rate_idx: Option<u32>,
+ signal: Option<u32>,
+ cookie: Option<u64>,
+ freq: Option<u32>,
+ tx_info: Option<Vec<TxRate>>,
+ tx_info_flags: Option<Vec<TxRateFlag>>,
+ attributes: Vec<u8>,
+}
+
+#[derive(Debug)]
+pub struct HwsimAttrSet {
+ pub transmitter: Option<MacAddress>,
+ pub receiver: Option<MacAddress>,
+ pub frame: Option<Vec<u8>>,
+ pub flags: Option<u32>,
+ pub rx_rate_idx: Option<u32>,
+ pub signal: Option<u32>,
+ pub cookie: Option<u64>,
+ pub freq: Option<u32>,
+ pub tx_info: Option<Vec<TxRate>>,
+ pub tx_info_flags: Option<Vec<TxRateFlag>>,
+ pub attributes: Vec<u8>,
+}
+
+/// Builder pattern for each of the HWSIM_ATTR used in conjunction
+/// with the HwsimAttr packet formats defined in `mac80211_hwsim.pdl`
+///
+/// Used during `parse` or to create new HwsimCmd packets containing
+/// an attributes vector.
+///
+impl HwsimAttrSetBuilder {
+ // Add packet to the attributes vec and pad for proper NLA
+ // alignment. This provides for to_bytes for a HwsimMsg for
+ // packets constructed by the Builder.
+
+ fn extend_attributes<P: Packet>(&mut self, packet: P) {
+ let mut vec: Vec<u8> = packet.to_vec();
+ let nla_padding = nla_align(vec.len()) - vec.len();
+ vec.extend(vec![0; nla_padding]);
+ self.attributes.extend(vec);
+ }
+
+ 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.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.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.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.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.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.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.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.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.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.tx_info_flags = Some(tx_rate_flags.to_vec());
+ self
+ }
+
+ pub fn build(mut self) -> anyhow::Result<HwsimAttrSet> {
+ Ok(HwsimAttrSet {
+ transmitter: self.transmitter,
+ receiver: self.receiver,
+ cookie: self.cookie,
+ flags: self.flags,
+ rx_rate_idx: self.rx_rate_idx,
+ signal: self.signal,
+ frame: self.frame,
+ freq: self.freq,
+ tx_info: self.tx_info,
+ tx_info_flags: self.tx_info_flags,
+ attributes: self.attributes,
+ })
+ }
+}
+
+impl HwsimAttrSet {
+ /// Creates a new `HwsimAttrSetBuilder` with default settings, ready for configuring attributes.
+ ///
+ /// # Returns
+ ///
+ /// * A new `HwsimAttrSetBuilder` instance, initialized with default values.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// let mut builder = HwsimAttrSetBuilder::builder();
+ /// builder.signal(42).cookie(32); // Example attribute configuration
+ /// let attr_set = builder.build();
+ /// ```
+ pub fn builder() -> HwsimAttrSetBuilder {
+ HwsimAttrSetBuilder::default()
+ }
+
+ /// Parse and validates the attributes from a HwsimMsg command.
+ pub fn parse(attributes: &[u8]) -> anyhow::Result<HwsimAttrSet> {
+ let mut index: usize = 0;
+ 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_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() {
+ HwsimAttrAddrTransmitter(child) => builder.transmitter(child.get_address()),
+ HwsimAttrAddrReceiver(child) => builder.receiver(child.get_address()),
+ HwsimAttrFrame(child) => builder.frame(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()),
+ _ => {
+ return Err(anyhow!(
+ "Invalid attribute message: {:?}",
+ hwsim_attr.get_nla_type() as u32
+ ))
+ }
+ };
+ // Manually step through the attribute bytes aligning as
+ // we go because netlink aligns each attribute which isn't
+ // a feature of PDL parser.
+ index += nla_align(nla_len);
+ }
+ builder.build()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ // Validate `HwsimAttrSet` attribute parsing from byte vector.
+ #[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();
+
+ // Validate each attribute parsed
+ assert_eq!(attrs.transmitter, MacAddress::try_from(11670786u64).ok());
+ assert!(attrs.receiver.is_none());
+ assert!(attrs.frame.is_some());
+ assert_eq!(attrs.flags, Some(2));
+ assert!(attrs.rx_rate_idx.is_none());
+ assert!(attrs.signal.is_none());
+ assert_eq!(attrs.cookie, Some(201));
+ assert_eq!(attrs.freq, Some(2422));
+ assert!(attrs.tx_info.is_some());
+ }
+
+ // Validate the contents of the `attributes` bytes constructed by
+ // the Builder by matching with the bytes containing the input
+ // attributes. Confirms attribute order, packet format and
+ // padding.
+ #[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());
+ }
+}
diff --git a/rust/daemon/src/wifi/ieee80211.rs b/rust/daemon/src/wifi/ieee80211.rs
index 7e501b8..64bc61b 100644
--- a/rust/daemon/src/wifi/ieee80211.rs
+++ b/rust/daemon/src/wifi/ieee80211.rs
@@ -20,13 +20,26 @@ include!(concat!(env!("OUT_DIR"), "/ieee80211_packets.rs"));
/// A Ieee80211 MAC address
+// TODO: Add unit tests.
impl fmt::Display for MacAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let bytes = u64::to_le_bytes(self.0);
write!(
f,
- "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
- bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0],
+ "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
+ bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5],
+ )
+ }
+}
+
+impl fmt::Display for Ieee80211 {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "{{ds: {}, src: {}, dst: {}}}",
+ self.get_ds(),
+ self.get_source(),
+ self.get_destination()
)
}
}
@@ -44,6 +57,13 @@ impl From<MacAddress> for [u8; 6] {
}
}
+impl MacAddress {
+ pub fn is_multicast(&self) -> bool {
+ let addr = u64::to_le_bytes(self.0);
+ addr[0] == 0x1
+ }
+}
+
impl Ieee80211 {
// Frame has addr4 field
pub fn has_a4(&self) -> bool {
@@ -66,6 +86,17 @@ impl Ieee80211 {
&& self.ieee80211.stype == (ManagementSubType::ProbeReq as u8)
}
+ pub fn get_ds(&self) -> String {
+ match self.specialize() {
+ Ieee80211Child::Ieee80211ToAp(hdr) => "ToAp",
+ Ieee80211Child::Ieee80211FromAp(hdr) => "FromAp",
+ Ieee80211Child::Ieee80211Ibss(hdr) => "Ibss",
+ Ieee80211Child::Ieee80211Wds(hdr) => "Wds",
+ _ => panic!("unexpected specialized header"),
+ }
+ .to_string()
+ }
+
pub fn get_source(&self) -> MacAddress {
match self.specialize() {
Ieee80211Child::Ieee80211ToAp(hdr) => hdr.get_source(),
@@ -75,6 +106,19 @@ impl Ieee80211 {
_ => panic!("unexpected specialized header"),
}
}
+
+ /// Ieee80211 packets have 3-4 addresses in different positions based
+ /// on the FromDS and ToDS flags. This function gets the destination
+ /// address depending on the FromDS+ToDS packet subtypes.
+ pub fn get_destination(&self) -> MacAddress {
+ match self.specialize() {
+ Ieee80211Child::Ieee80211ToAp(hdr) => hdr.get_destination(),
+ Ieee80211Child::Ieee80211FromAp(hdr) => hdr.get_destination(),
+ Ieee80211Child::Ieee80211Ibss(hdr) => hdr.get_destination(),
+ Ieee80211Child::Ieee80211Wds(hdr) => hdr.get_destination(),
+ _ => panic!("unexpected specialized header"),
+ }
+ }
}
fn parse_mac_address(s: &str) -> Option<MacAddress> {
@@ -116,4 +160,14 @@ mod tests {
let b = format!("{}", parse_mac_address("00:0b:85:71:20:ce").unwrap());
assert_eq!(a, b);
}
+
+ #[test]
+ fn test_is_multicast() {
+ // Multicast MAC address: 01:00:5E:00:00:FB
+ let mdns_mac_address = parse_mac_address("01:00:5e:00:00:fb").unwrap();
+ assert!(mdns_mac_address.is_multicast());
+ // Source address: Cisco_71:20:ce (00:0b:85:71:20:ce)
+ let non_mdns_mac_address = parse_mac_address("00:0b:85:71:20:ce").unwrap();
+ assert!(!non_mdns_mac_address.is_multicast());
+ }
}
diff --git a/rust/daemon/src/wifi/medium.rs b/rust/daemon/src/wifi/medium.rs
index 11454df..c5c4739 100644
--- a/rust/daemon/src/wifi/medium.rs
+++ b/rust/daemon/src/wifi/medium.rs
@@ -12,17 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use super::packets::mac80211_hwsim::{HwsimAttr, HwsimCmd, HwsimMsg, HwsimMsgHdr};
-use super::packets::netlink::{NlAttrHdr, NlMsgHdr};
+use super::ieee80211::MacAddress;
+use super::packets::mac80211_hwsim::{HwsimAttr, HwsimCmd, HwsimMsg, HwsimMsgHdr, NlMsgHdr};
+use super::packets::netlink::NlAttrHdr;
+use crate::devices::chip::ChipIdentifier;
use crate::wifi::frame::Frame;
+use crate::wifi::hwsim_attr_set::HwsimAttrSet;
+use crate::wifi::packets::mac80211_hwsim::HwsimMsgBuilder;
use anyhow::{anyhow, Context};
-use log::{info, warn};
-
-const NLA_ALIGNTO: usize = 4;
-
-fn nla_align(len: usize) -> usize {
- len.wrapping_add(NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)
-}
+use log::{debug, info, warn};
+use pdl_runtime::Packet;
+use std::collections::{HashMap, HashSet};
#[derive(Debug)]
pub enum HwsimCmdEnum {
@@ -37,71 +37,161 @@ pub enum HwsimCmdEnum {
DelMacAddr,
}
-pub fn parse_hwsim_cmd(packet: &[u8]) -> anyhow::Result<HwsimCmdEnum> {
- match HwsimMsg::parse(packet) {
- Ok(hwsim_msg) => match (hwsim_msg.hwsim_hdr.hwsim_cmd) {
+struct Station {
+ client_id: u32,
+ addr: MacAddress, // virtual interface mac address
+}
+
+pub struct Medium {
+ callback: HwsimCmdCallback,
+ stations: HashMap<MacAddress, Station>,
+}
+
+type HwsimCmdCallback = fn(u32, &[u8]);
+
+impl Medium {
+ pub fn new(callback: HwsimCmdCallback) -> Medium {
+ Self { callback, stations: HashMap::new() }
+ }
+ fn get_station_by_addr(&self, addr: MacAddress) -> Option<&Station> {
+ self.stations.get(&addr)
+ }
+}
+
+impl Station {
+ fn new(client_id: u32, addr: MacAddress) -> Self {
+ Self { client_id, addr }
+ }
+}
+
+/// Process commands from the kernel's mac80211_hwsim subsystem.
+///
+/// This is the processing that will be implemented:
+///
+/// * The source MacAddress in 802.11 frames is re-mapped to a globally
+/// unique MacAddress because resumed Emulator AVDs appear with the
+/// same address.
+///
+/// * 802.11 frames sent between stations
+///
+/// * 802.11 multicast frames are re-broadcast to connected stations.
+///
+
+impl Medium {
+ pub fn process(&mut self, client_id: u32, packet: &[u8]) -> bool {
+ match self.process_internal(client_id, packet) {
+ Ok(b) => b,
+ Err(e) => {
+ warn!("error processing wifi {e}");
+ // continue processing hwsim cmd on error
+ false
+ }
+ }
+ }
+
+ fn process_internal(&mut self, client_id: u32, packet: &[u8]) -> anyhow::Result<bool> {
+ let hwsim_msg = HwsimMsg::parse(packet)?;
+ match (hwsim_msg.get_hwsim_hdr().hwsim_cmd) {
HwsimCmd::Frame => {
- let frame = Frame::new(&hwsim_msg.attributes)?;
- Ok(HwsimCmdEnum::Frame(Box::new(frame)))
+ let frame = Frame::parse(&hwsim_msg)?;
+ info!(
+ "Frame chip {}, addr {}, flags {}, cookie {:?}, ieee80211 {}",
+ client_id, frame.transmitter, frame.flags, frame.cookie, frame.ieee80211
+ );
+ let addr = frame.transmitter;
+ // Creates Stations on the fly when there is no config file
+ let _ = self.stations.entry(addr).or_insert_with(|| Station::new(client_id, addr));
+ let sender = self.stations.get(&addr).unwrap();
+ self.queue_frame(sender, frame)
+ }
+ HwsimCmd::AddMacAddr => {
+ let attr_set = HwsimAttrSet::parse(hwsim_msg.get_attributes())?;
+ if let (Some(addr), Some(hwaddr)) = (attr_set.transmitter, attr_set.receiver) {
+ info!("ADD_MAC_ADDR transmitter {:?} receiver {:?}", hwaddr, addr);
+ } else {
+ warn!("ADD_MAC_ADDR missing transmitter or receiver");
+ }
+ Ok(false)
}
- _ => Err(anyhow!("Unknown HwsimkMsg cmd={:?}", hwsim_msg.hwsim_hdr.hwsim_cmd)),
+ HwsimCmd::DelMacAddr => {
+ let attr_set = HwsimAttrSet::parse(hwsim_msg.get_attributes())?;
+ if let (Some(addr), Some(hwaddr)) = (attr_set.transmitter, attr_set.receiver) {
+ info!("DEL_MAC_ADDR transmitter {:?} receiver {:?}", hwaddr, addr);
+ } else {
+ warn!("DEL_MAC_ADDR missing transmitter or receiver");
+ }
+ Ok(false)
+ }
+ _ => {
+ info!("Another command found {:?}", hwsim_msg);
+ Ok(false)
+ }
+ }
+ }
+
+ fn queue_frame(&self, station: &Station, frame: Frame) -> anyhow::Result<bool> {
+ let destination = frame.ieee80211.get_destination();
+ if let Some(station) = self.stations.get(&destination) {
+ info!("Frame deliver from {} to {}", station.addr, destination);
+ // rewrite packet to destination client: ToAP -> FromAP
+ Ok(true)
+ } else if destination.is_multicast() {
+ info!("Frame multicast {}", frame.ieee80211);
+ Ok(true)
+ } else {
+ // pass to libslirp
+ Ok(false)
+ }
+ }
+}
+
+fn build_tx_info(hwsim_msg: &HwsimMsg) -> anyhow::Result<HwsimMsg> {
+ let attrs = HwsimAttrSet::parse(hwsim_msg.get_attributes()).context("HwsimAttrSet").unwrap();
+
+ let hwsim_hdr = hwsim_msg.get_hwsim_hdr();
+ let nl_hdr = hwsim_msg.get_nl_hdr();
+ let mut new_attr_builder = HwsimAttrSet::builder();
+ const SIGNAL: u32 = 4294967246;
+
+ new_attr_builder
+ .transmitter(&attrs.transmitter.context("transmitter")?.into())
+ .flags(attrs.flags.context("flags")?)
+ .cookie(attrs.cookie.context("cookie")?)
+ .signal(attrs.signal.unwrap_or(SIGNAL))
+ .tx_info(attrs.tx_info.context("tx_info")?.as_slice());
+
+ 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 {
+ attributes: new_attr.attributes,
+ hwsim_hdr: HwsimMsgHdr {
+ hwsim_cmd: HwsimCmd::TxInfoFrame,
+ hwsim_version: hwsim_hdr.hwsim_version,
+ reserved: hwsim_hdr.reserved,
+ },
+ nl_hdr: NlMsgHdr {
+ nlmsg_len,
+ nlmsg_type: nl_hdr.nlmsg_type,
+ nlmsg_flags: nl_hdr.nlmsg_flags,
+ nlmsg_seq: 0,
+ nlmsg_pid: 0,
},
- Err(e) => Err(anyhow!("Unable to parse netlink message! {:?}", e)),
}
+ .build();
+ Ok(new_hwsim_msg)
}
-pub fn test_parse_hwsim_cmd() {
- let packet: Vec<u8> = vec![
- 188, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 10, 0, 2, 0, 2, 21, 178, 0,
- 0, 0, 0, 0, 98, 0, 3, 0, 64, 0, 0, 0, 255, 255, 255, 255, 255, 255, 74, 129, 38, 251, 211,
- 154, 255, 255, 255, 255, 255, 255, 128, 12, 0, 0, 1, 8, 2, 4, 11, 22, 12, 18, 24, 36, 50,
- 4, 48, 72, 96, 108, 45, 26, 126, 16, 27, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 255, 22, 35, 1, 120, 200, 26, 64, 0, 0, 191, 206, 0, 0, 0, 0, 0, 0,
- 0, 0, 250, 255, 250, 255, 0, 0, 8, 0, 4, 0, 2, 0, 0, 0, 8, 0, 19, 0, 118, 9, 0, 0, 12, 0,
- 7, 0, 0, 1, 255, 0, 255, 0, 255, 0, 16, 0, 21, 0, 0, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0,
- 12, 0, 8, 0, 201, 0, 0, 0, 0, 0, 0, 0,
- ];
- assert!(parse_hwsim_cmd(&packet).is_ok());
-
- // missing transmitter attribute
- let packet2: Vec<u8> = vec![
- 132, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 10, 0, 1, 0, 2, 21, 178, 0,
- 0, 0, 0, 0, 76, 0, 3, 0, 8, 2, 0, 0, 2, 21, 178, 0, 0, 0, 0, 19, 16, 133, 254, 1, 82, 85,
- 10, 0, 2, 2, 0, 0, 170, 170, 3, 0, 0, 0, 8, 0, 69, 0, 0, 40, 0, 14, 0, 0, 64, 6, 177, 19,
- 142, 251, 46, 164, 10, 0, 2, 16, 1, 187, 198, 28, 0, 0, 250, 220, 35, 200, 197, 208, 80,
- 16, 255, 255, 57, 216, 0, 0, 8, 0, 5, 0, 1, 0, 0, 0, 8, 0, 6, 0, 206, 255, 255, 255, 8, 0,
- 19, 0, 143, 9, 0, 0,
- ];
- assert!(parse_hwsim_cmd(&packet2).is_ok());
-
- // missing cookie attribute
- let packet3: Vec<u8> = vec![
- 144, 1, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 10, 0, 1, 0, 2, 21, 178, 0,
- 0, 0, 0, 0, 85, 1, 3, 0, 128, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 19, 16, 133, 254,
- 1, 0, 19, 16, 133, 254, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 3, 1, 4, 0, 11, 65, 110, 100,
- 114, 111, 105, 100, 87, 105, 102, 105, 1, 4, 130, 132, 139, 150, 3, 1, 8, 42, 1, 7, 45, 26,
- 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 22, 8,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 4, 0, 0, 0, 2, 128, 0,
- 0, 0, 255, 255, 255, 255, 255, 255, 0, 19, 16, 133, 254, 1, 0, 19, 16, 133, 254, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 232, 3, 1, 4, 0, 11, 65, 110, 100, 114, 111, 105, 100, 87, 105,
- 102, 105, 1, 4, 130, 132, 139, 150, 3, 1, 8, 42, 1, 7, 45, 26, 12, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 22, 8, 0, 19, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 4, 0, 0, 0, 2, 16, 0, 0, 0, 2, 21, 178, 0, 0, 0,
- 0, 19, 16, 133, 254, 1, 0, 19, 16, 133, 254, 1, 0, 0, 1, 4, 0, 0, 1, 192, 1, 4, 130, 132,
- 139, 150, 45, 26, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 61, 22, 8, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 4, 0,
- 0, 0, 2, 90, 3, 36, 1, 0, 0, 0, 0, 8, 0, 5, 0, 1, 0, 0, 0, 8, 0, 6, 0, 206, 255, 255, 255,
- 8, 0, 19, 0, 143, 9, 0, 0,
- ];
- assert!(parse_hwsim_cmd(&packet3).is_ok());
-
- // HwsimkMsg cmd=TxInfoFrame packet
- let packet3: Vec<u8> = vec![
- 72, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 10, 0, 2, 0, 2, 21, 178, 0,
- 0, 0, 0, 0, 8, 0, 4, 0, 4, 0, 0, 0, 12, 0, 8, 0, 60, 0, 0, 0, 0, 0, 0, 0, 8, 0, 6, 0, 206,
- 255, 255, 255, 12, 0, 7, 0, 3, 0, 0, 0, 0, 0, 255, 0,
- ];
- assert!(parse_hwsim_cmd(&packet3).is_err());
+// It's usd 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) {
+ HwsimCmd::Frame => {
+ let frame = Frame::parse(&hwsim_msg)?;
+ Ok(HwsimCmdEnum::Frame(Box::new(frame)))
+ }
+ _ => Err(anyhow!("Unknown HwsimMsg cmd={:?}", hwsim_msg.get_hwsim_hdr().hwsim_cmd)),
+ }
}
#[cfg(test)]
@@ -110,6 +200,50 @@ mod tests {
#[test]
fn test_netlink_attr() {
- test_parse_hwsim_cmd();
+ let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
+ assert!(parse_hwsim_cmd(&packet).is_ok());
+
+ // missing transmitter attribute
+ let packet2: Vec<u8> = include!("test_packets/hwsim_cmd_frame2.csv");
+ assert!(parse_hwsim_cmd(&packet2).is_err());
+
+ // missing cookie attribute
+ let packet3: Vec<u8> = include!("test_packets/hwsim_cmd_frame_no_cookie.csv");
+ assert!(parse_hwsim_cmd(&packet3).is_err());
+
+ // HwsimkMsg cmd=TxInfoFrame packet
+ let packet3: Vec<u8> = include!("test_packets/hwsim_cmd_tx_info.csv");
+ assert!(parse_hwsim_cmd(&packet3).is_err());
+ }
+
+ #[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 mdns_frame = Frame::parse(&hwsim_msg).unwrap();
+ assert!(mdns_frame.ieee80211.get_destination().is_multicast());
+
+ let packet: Vec<u8> = include!("test_packets/hwsim_cmd_frame.csv");
+ let hwsim_msg = HwsimMsg::parse(&packet).unwrap();
+ let non_mdns_frame = Frame::parse(&hwsim_msg).unwrap();
+ assert!(!non_mdns_frame.ieee80211.get_destination().is_multicast());
+ }
+
+ #[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 new_hwsim_msg = build_tx_info(&hwsim_msg).unwrap();
+ assert_eq!(hwsim_msg, new_hwsim_msg);
+ }
+
+ #[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_tx_info = build_tx_info(&hwsim_msg).unwrap();
+ assert_eq!(hwsim_msg_tx_info.get_hwsim_hdr().hwsim_cmd, HwsimCmd::TxInfoFrame);
}
}
diff --git a/rust/daemon/src/wifi/mod.rs b/rust/daemon/src/wifi/mod.rs
index 8891cce..80842a8 100644
--- a/rust/daemon/src/wifi/mod.rs
+++ b/rust/daemon/src/wifi/mod.rs
@@ -18,6 +18,7 @@
#![allow(unused)]
pub(crate) mod frame;
+pub(crate) mod hwsim_attr_set;
pub(crate) mod ieee80211;
pub(crate) mod medium;
pub(crate) mod packets;
diff --git a/rust/daemon/src/wifi/test_packets/hwsim_cmd_frame.csv b/rust/daemon/src/wifi/test_packets/hwsim_cmd_frame.csv
new file mode 100644
index 0000000..34420fe
--- /dev/null
+++ b/rust/daemon/src/wifi/test_packets/hwsim_cmd_frame.csv
@@ -0,0 +1 @@
+vec![188, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 10, 0, 2, 0, 2, 21, 178, 0, 0, 0, 0, 0, 98, 0, 3, 0, 64, 0, 0, 0, 255, 255, 255, 255, 255, 255, 74, 129, 38, 251, 211, 154, 255, 255, 255, 255, 255, 255, 128, 12, 0, 0, 1, 8, 2, 4, 11, 22, 12, 18, 24, 36, 50, 4, 48, 72, 96, 108, 45, 26, 126, 16, 27, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 22, 35, 1, 120, 200, 26, 64, 0, 0, 191, 206, 0, 0, 0, 0, 0, 0, 0, 0, 250, 255, 250, 255, 0, 0, 8, 0, 4, 0, 2, 0, 0, 0, 8, 0, 19, 0, 118, 9, 0, 0, 12, 0, 7, 0, 0, 1, 255, 0, 255, 0, 255, 0, 16, 0, 21, 0, 0, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 12, 0, 8, 0, 201, 0, 0, 0, 0, 0, 0, 0]
diff --git a/rust/daemon/src/wifi/test_packets/hwsim_cmd_frame2.csv b/rust/daemon/src/wifi/test_packets/hwsim_cmd_frame2.csv
new file mode 100644
index 0000000..378bf2c
--- /dev/null
+++ b/rust/daemon/src/wifi/test_packets/hwsim_cmd_frame2.csv
@@ -0,0 +1 @@
+vec![132, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 10, 0, 1, 0, 2, 21, 178, 0, 0, 0, 0, 0, 76, 0, 3, 0, 8, 2, 0, 0, 2, 21, 178, 0, 0, 0, 0, 19, 16, 133, 254, 1, 82, 85, 10, 0, 2, 2, 0, 0, 170, 170, 3, 0, 0, 0, 8, 0, 69, 0, 0, 40, 0, 14, 0, 0, 64, 6, 177, 19, 142, 251, 46, 164, 10, 0, 2, 16, 1, 187, 198, 28, 0, 0, 250, 220, 35, 200, 197, 208, 80, 16, 255, 255, 57, 216, 0, 0, 8, 0, 5, 0, 1, 0, 0, 0, 8, 0, 6, 0, 206, 255, 255, 255, 8, 0, 19, 0, 143, 9, 0, 0] \ No newline at end of file
diff --git a/rust/daemon/src/wifi/test_packets/hwsim_cmd_frame_mdns.csv b/rust/daemon/src/wifi/test_packets/hwsim_cmd_frame_mdns.csv
new file mode 100644
index 0000000..76b8f4c
--- /dev/null
+++ b/rust/daemon/src/wifi/test_packets/hwsim_cmd_frame_mdns.csv
@@ -0,0 +1 @@
+vec![160, 2, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 10, 0, 2, 0, 2, 21, 178, 0, 0, 0, 0, 0, 71, 2, 3, 0, 8, 1, 58, 1, 0, 19, 16, 133, 254, 1, 2, 21, 178, 0, 0, 0, 1, 0, 94, 0, 0, 251, 160, 8, 170, 170, 3, 0, 0, 0, 8, 0, 69, 0, 2, 35, 114, 146, 64, 0, 255, 17, 26, 44, 10, 0, 2, 16, 224, 0, 0, 251, 20, 233, 20, 233, 2, 15, 158, 47, 0, 0, 132, 0, 0, 0, 0, 12, 0, 0, 0, 5, 21, 97, 100, 98, 45, 69, 77, 85, 76, 65, 84, 79, 82, 51, 52, 88, 49, 88, 49, 51, 88, 48, 4, 95, 97, 100, 98, 4, 95, 116, 99, 112, 5, 108, 111, 99, 97, 108, 0, 0, 16, 128, 1, 0, 0, 17, 148, 0, 1, 0, 9, 95, 115, 101, 114, 118, 105, 99, 101, 115, 7, 95, 100, 110, 115, 45, 115, 100, 4, 95, 117, 100, 112, 192, 44, 0, 12, 0, 1, 0, 0, 17, 148, 0, 2, 192, 34, 192, 34, 0, 12, 0, 1, 0, 0, 17, 148, 0, 2, 192, 12, 192, 12, 0, 33, 128, 1, 0, 0, 0, 120, 0, 16, 0, 0, 0, 0, 21, 179, 7, 65, 110, 100, 114, 111, 105, 100, 192, 44, 45, 87, 105, 70, 105, 84, 101, 115, 116, 45, 55, 49, 52, 102, 50, 54, 56, 52, 45, 101, 102, 101, 52, 45, 52, 55, 97, 100, 45, 97, 55, 53, 99, 45, 100, 55, 97, 101, 100, 101, 54, 55, 55, 56, 99, 102, 10, 95, 119, 105, 102, 105, 95, 116, 101, 115, 116, 192, 39, 0, 16, 128, 1, 0, 0, 17, 148, 0, 1, 0, 192, 62, 0, 12, 0, 1, 0, 0, 17, 148, 0, 2, 192, 187, 192, 187, 0, 12, 0, 1, 0, 0, 17, 148, 0, 2, 192, 141, 192, 141, 0, 33, 128, 1, 0, 0, 0, 120, 0, 8, 0, 0, 0, 0, 129, 135, 192, 131, 2, 49, 54, 1, 50, 1, 48, 2, 49, 48, 7, 105, 110, 45, 97, 100, 100, 114, 4, 97, 114, 112, 97, 0, 0, 12, 128, 1, 0, 0, 0, 120, 0, 2, 192, 131, 1, 55, 1, 50, 1, 53, 1, 49, 1, 57, 1, 52, 1, 51, 1, 65, 1, 56, 1, 52, 1, 56, 1, 55, 1, 55, 1, 53, 1, 55, 1, 53, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 56, 1, 69, 1, 70, 3, 105, 112, 54, 193, 21, 0, 12, 128, 1, 0, 0, 0, 120, 0, 2, 192, 131, 192, 131, 0, 1, 128, 1, 0, 0, 0, 120, 0, 4, 10, 0, 2, 16, 192, 131, 0, 28, 128, 1, 0, 0, 0, 120, 0, 16, 254, 128, 0, 0, 0, 0, 0, 0, 87, 87, 120, 72, 163, 73, 21, 39, 192, 12, 0, 47, 128, 1, 0, 0, 17, 148, 0, 9, 192, 12, 0, 5, 0, 0, 128, 0, 64, 192, 141, 0, 47, 128, 1, 0, 0, 17, 148, 0, 9, 192, 141, 0, 5, 0, 0, 128, 0, 64, 193, 3, 0, 47, 128, 1, 0, 0, 0, 120, 0, 6, 193, 3, 0, 2, 0, 8, 193, 39, 0, 47, 128, 1, 0, 0, 0, 120, 0, 6, 193, 39, 0, 2, 0, 8, 192, 131, 0, 47, 128, 1, 0, 0, 0, 120, 0, 8, 192, 131, 0, 4, 64, 0, 0, 8, 0, 8, 0, 4, 0, 0, 0, 0, 0, 8, 0, 19, 0, 143, 9, 0, 0, 12, 0, 7, 0, 0, 2, 0, 2, 0, 2, 255, 0, 16, 0, 21, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 255, 0, 0, 12, 0, 8, 0, 139, 0, 0, 0, 0, 0, 0, 0] \ No newline at end of file
diff --git a/rust/daemon/src/wifi/test_packets/hwsim_cmd_frame_no_cookie.csv b/rust/daemon/src/wifi/test_packets/hwsim_cmd_frame_no_cookie.csv
new file mode 100644
index 0000000..24177df
--- /dev/null
+++ b/rust/daemon/src/wifi/test_packets/hwsim_cmd_frame_no_cookie.csv
@@ -0,0 +1 @@
+vec![144, 1, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 10, 0, 1, 0, 2, 21, 178, 0, 0, 0, 0, 0, 85, 1, 3, 0, 128, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 19, 16, 133, 254, 1, 0, 19, 16, 133, 254, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 3, 1, 4, 0, 11, 65, 110, 100, 114, 111, 105, 100, 87, 105, 102, 105, 1, 4, 130, 132, 139, 150, 3, 1, 8, 42, 1, 7, 45, 26, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 22, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 4, 0, 0, 0, 2, 128, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 19, 16, 133, 254, 1, 0, 19, 16, 133, 254, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 3, 1, 4, 0, 11, 65, 110, 100, 114, 111, 105, 100, 87, 105, 102, 105, 1, 4, 130, 132, 139, 150, 3, 1, 8, 42, 1, 7, 45, 26, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 22, 8, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 4, 0, 0, 0, 2, 16, 0, 0, 0, 2, 21, 178, 0, 0, 0, 0, 19, 16, 133, 254, 1, 0, 19, 16, 133, 254, 1, 0, 0, 1, 4, 0, 0, 1, 192, 1, 4, 130, 132, 139, 150, 45, 26, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 22, 8, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 4, 0, 0, 0, 2, 90, 3, 36, 1, 0, 0, 0, 0, 8, 0, 5, 0, 1, 0, 0, 0, 8, 0, 6, 0, 206, 255, 255, 255, 8, 0, 19, 0, 143, 9, 0, 0] \ No newline at end of file
diff --git a/rust/daemon/src/wifi/test_packets/hwsim_cmd_tx_info.csv b/rust/daemon/src/wifi/test_packets/hwsim_cmd_tx_info.csv
new file mode 100644
index 0000000..fd9a9cd
--- /dev/null
+++ b/rust/daemon/src/wifi/test_packets/hwsim_cmd_tx_info.csv
@@ -0,0 +1 @@
+vec![72, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 10, 0, 2, 0, 2, 21, 178, 0, 0, 0, 0, 0, 8, 0, 4, 0, 4, 0, 0, 0, 12, 0, 8, 0, 60, 0, 0, 0, 0, 0, 0, 0, 8, 0, 6, 0, 206, 255, 255, 255, 12, 0, 7, 0, 3, 0, 0, 0, 0, 0, 255, 0] \ No newline at end of file
diff --git a/rust/frontend/Cargo.toml b/rust/frontend/Cargo.toml
new file mode 100644
index 0000000..9d5f308
--- /dev/null
+++ b/rust/frontend/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "frontend"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+protobuf = "3.2.0"
+protoc-grpcio = "3.0.0"
+protoc-rust = "2.27"
+grpcio = "0.13.0"
+grpcio-sys = "0.12.1"
+futures = "0.3.26"
+
+##[build-dependencies]
+##protoc-grpcio = "3.0.0"
+
+##[[bin]]
+##name = "server"
+##path = "src/server.rs"
+
+##[[bin]]
+##name = "netsim-grpc"
+##path = "src/client.rs" \ No newline at end of file
diff --git a/rust/frontend/src/netsim_test_client.rs b/rust/frontend/src/netsim_test_client.rs
new file mode 100644
index 0000000..b65d256
--- /dev/null
+++ b/rust/frontend/src/netsim_test_client.rs
@@ -0,0 +1,30 @@
+//! netsim Rust grpc test client
+
+use std::env;
+use std::sync::Arc;
+
+use grpcio::{ChannelBuilder, EnvBuilder};
+use netsim_common::util::os_utils::get_server_address;
+use netsim_proto::frontend_grpc::FrontendServiceClient;
+
+fn main() {
+ let args: Vec<String> = env::args().collect();
+ let server_addr: String = if args.len() > 1 {
+ args[1].to_owned()
+ } else {
+ match get_server_address(1) {
+ Some(addr) => addr,
+ None => {
+ println!("Unable to get server address.");
+ return;
+ }
+ }
+ };
+ let env = Arc::new(EnvBuilder::new().build());
+
+ let ch = ChannelBuilder::new(env).connect(&server_addr);
+ let client = FrontendServiceClient::new(ch);
+
+ let reply = client.get_version(&::protobuf::well_known_types::empty::Empty::new()).unwrap();
+ println!("Version: {}", reply.version);
+}
diff --git a/rust/frontend/src/netsim_test_server.rs b/rust/frontend/src/netsim_test_server.rs
new file mode 100644
index 0000000..6cbf4f9
--- /dev/null
+++ b/rust/frontend/src/netsim_test_server.rs
@@ -0,0 +1,117 @@
+//! netsim Rust grpc test server
+use std::io::Read;
+use std::sync::Arc;
+use std::{io, thread};
+
+use futures::channel::oneshot;
+use futures::executor::block_on;
+use futures::prelude::*;
+use grpcio::{
+ ChannelBuilder, Environment, ResourceQuota, RpcContext, ServerBuilder, ServerCredentials,
+ UnarySink,
+};
+
+use netsim_proto::frontend::VersionResponse;
+use netsim_proto::frontend_grpc::{create_frontend_service, FrontendService};
+
+#[derive(Clone)]
+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()
+ };
+ let f = sink
+ .success(response)
+ .map_err(move |e| eprintln!("failed to reply {:?}: {:?}", 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>,
+ ) {
+ todo!()
+ }
+
+ fn patch_device(
+ &mut self,
+ _ctx: grpcio::RpcContext,
+ _req: netsim_proto::frontend::PatchDeviceRequest,
+ _sink: grpcio::UnarySink<protobuf::well_known_types::empty::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 patch_capture(
+ &mut self,
+ _ctx: grpcio::RpcContext,
+ _req: netsim_proto::frontend::PatchCaptureRequest,
+ _sink: grpcio::UnarySink<protobuf::well_known_types::empty::Empty>,
+ ) {
+ todo!()
+ }
+
+ fn list_capture(
+ &mut self,
+ _ctx: grpcio::RpcContext,
+ _req: protobuf::well_known_types::empty::Empty,
+ _sink: grpcio::UnarySink<netsim_proto::frontend::ListCaptureResponse>,
+ ) {
+ todo!()
+ }
+
+ fn get_capture(
+ &mut self,
+ _ctx: grpcio::RpcContext,
+ _req: netsim_proto::frontend::GetCaptureRequest,
+ _sink: grpcio::ServerStreamingSink<netsim_proto::frontend::GetCaptureResponse>,
+ ) {
+ todo!()
+ }
+}
+
+fn main() {
+ let env = Arc::new(Environment::new(1));
+ let service = create_frontend_service(FrontendClient);
+
+ let quota = ResourceQuota::new(Some("HelloServerQuota")).resize_memory(1024 * 1024);
+ let ch_builder = ChannelBuilder::new(env.clone()).set_resource_quota(quota);
+
+ let mut server = ServerBuilder::new(env)
+ .register_service(service)
+ .channel_args(ch_builder.build_args())
+ .build()
+ .unwrap();
+ let port = server.add_listening_port("127.0.0.1:50051", ServerCredentials::insecure()).unwrap();
+ server.start();
+ println!("listening on port {}", port);
+
+ let (tx, rx) = oneshot::channel();
+ thread::spawn(move || {
+ println!("Press ENTER to exit...");
+ let _ = io::stdin().read(&mut [0]).unwrap();
+ tx.send(())
+ });
+ let _ = block_on(rx);
+ let _ = block_on(server.shutdown());
+}
diff --git a/rust/proto/src/frontend.rs b/rust/proto/src/frontend.rs
index 053533b..a0227b3 100644
--- a/rust/proto/src/frontend.rs
+++ b/rust/proto/src/frontend.rs
@@ -1,5 +1,5 @@
// This file is generated by rust-protobuf 3.2.0. Do not edit
-// .proto file is parsed by protoc 3.21.12
+// .proto file is parsed by protoc --rust-out=...
// @generated
// https://github.com/rust-lang/rust-clippy/issues/702
@@ -25,10 +25,14 @@
/// of protobuf runtime.
const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0;
+/// Response of GetVersion.
+///
+/// Returns the version of the netsim service
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.VersionResponse)
pub struct VersionResponse {
// message fields
+ /// Version of netsim service
// @@protoc_insertion_point(field:netsim.frontend.VersionResponse.version)
pub version: ::std::string::String,
// special fields
@@ -147,10 +151,15 @@ impl ::protobuf::reflect::ProtobufValue for VersionResponse {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
+/// Request of CreateDevice.
+///
+/// CreateDevice is only used for built-in devices.
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.CreateDeviceRequest)
pub struct CreateDeviceRequest {
// message fields
+ /// DeviceCreate proto for creation. Check DeviceCreate in model.proto for more
+ /// detail.
// @@protoc_insertion_point(field:netsim.frontend.CreateDeviceRequest.device)
pub device: ::protobuf::MessageField<super::model::DeviceCreate>,
// special fields
@@ -270,10 +279,14 @@ impl ::protobuf::reflect::ProtobufValue for CreateDeviceRequest {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
+/// Response of CreateDevice.
+///
+/// Returns the device created in netsim
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.CreateDeviceResponse)
pub struct CreateDeviceResponse {
// message fields
+ /// Device proto
// @@protoc_insertion_point(field:netsim.frontend.CreateDeviceResponse.device)
pub device: ::protobuf::MessageField<super::model::Device>,
// special fields
@@ -393,10 +406,14 @@ impl ::protobuf::reflect::ProtobufValue for CreateDeviceResponse {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
+/// Request of DeleteDevice.
+///
+/// DeleteDevice is only used for built-in device.
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.DeleteChipRequest)
pub struct DeleteChipRequest {
// message fields
+ /// Device Identifier
// @@protoc_insertion_point(field:netsim.frontend.DeleteChipRequest.id)
pub id: u32,
// special fields
@@ -515,10 +532,16 @@ impl ::protobuf::reflect::ProtobufValue for DeleteChipRequest {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
+/// Request of PatchDevice.
+///
+/// You may patch the device position, orientation, and the radio states.
+/// For built-in devices, you may patch the specific configurations.
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.PatchDeviceRequest)
pub struct PatchDeviceRequest {
// message fields
+ /// Device proto. You must include either the id or name field to have
+ /// a successful patch.
// @@protoc_insertion_point(field:netsim.frontend.PatchDeviceRequest.device)
pub device: ::protobuf::MessageField<super::model::Device>,
// special fields
@@ -638,12 +661,20 @@ impl ::protobuf::reflect::ProtobufValue for PatchDeviceRequest {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
+/// Response for ListDevice request.
+///
+/// Returns the emulators and accessory devices that are connected to
+/// the network simulator.
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.ListDeviceResponse)
pub struct ListDeviceResponse {
// message fields
+ /// List of Device protos
// @@protoc_insertion_point(field:netsim.frontend.ListDeviceResponse.devices)
pub devices: ::std::vec::Vec<super::model::Device>,
+ /// Last modified timestamp for device resource.
+ /// The timestamp will be updated if devices state has changed (except for
+ /// packet counts)
// @@protoc_insertion_point(field:netsim.frontend.ListDeviceResponse.last_modified)
pub last_modified: ::protobuf::MessageField<::protobuf::well_known_types::timestamp::Timestamp>,
// special fields
@@ -780,10 +811,14 @@ impl ::protobuf::reflect::ProtobufValue for ListDeviceResponse {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
+/// Request for SubscribeDevice.
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.SubscribeDeviceRequest)
pub struct SubscribeDeviceRequest {
// message fields
+ /// The SubscribeDevice will immediately return if the
+ /// provided last_modified timestamp is prior to the current last_modified
+ /// timestamp in device resource.
// @@protoc_insertion_point(field:netsim.frontend.SubscribeDeviceRequest.last_modified)
pub last_modified: ::protobuf::MessageField<::protobuf::well_known_types::timestamp::Timestamp>,
// special fields
@@ -903,6 +938,7 @@ impl ::protobuf::reflect::ProtobufValue for SubscribeDeviceRequest {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
+/// Response for SubscribeDevice request.
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.SubscribeDeviceResponse)
pub struct SubscribeDeviceResponse {
@@ -1182,12 +1218,15 @@ pub mod subscribe_device_response {
}
}
+/// Request of PatchCapture.
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.PatchCaptureRequest)
pub struct PatchCaptureRequest {
// message fields
+ /// Capture Identifier
// @@protoc_insertion_point(field:netsim.frontend.PatchCaptureRequest.id)
pub id: u32,
+ /// PatchCapture proto
// @@protoc_insertion_point(field:netsim.frontend.PatchCaptureRequest.patch)
pub patch: ::protobuf::MessageField<patch_capture_request::PatchCapture>,
// special fields
@@ -1325,10 +1364,13 @@ impl ::protobuf::reflect::ProtobufValue for PatchCaptureRequest {
/// Nested message and enums of message `PatchCaptureRequest`
pub mod patch_capture_request {
+ /// Body of PatchCapture that will be channeled into
+ /// body for HandleCaptureCxx
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.PatchCaptureRequest.PatchCapture)
pub struct PatchCapture {
// message fields
+ /// Capture state
// @@protoc_insertion_point(field:netsim.frontend.PatchCaptureRequest.PatchCapture.state)
pub state: ::protobuf::EnumOrUnknown<super::super::model::State>,
// special fields
@@ -1448,10 +1490,14 @@ pub mod patch_capture_request {
}
}
+/// Response of ListCapture
+///
+/// Returns all capture information of devices connected to netsim.
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.ListCaptureResponse)
pub struct ListCaptureResponse {
// message fields
+ /// List of Capture protos
// @@protoc_insertion_point(field:netsim.frontend.ListCaptureResponse.captures)
pub captures: ::std::vec::Vec<super::model::Capture>,
// special fields
@@ -1571,10 +1617,12 @@ impl ::protobuf::reflect::ProtobufValue for ListCaptureResponse {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
+/// Request of GetCapture
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.GetCaptureRequest)
pub struct GetCaptureRequest {
// message fields
+ /// Capture Identifier
// @@protoc_insertion_point(field:netsim.frontend.GetCaptureRequest.id)
pub id: u32,
// special fields
@@ -1693,10 +1741,15 @@ impl ::protobuf::reflect::ProtobufValue for GetCaptureRequest {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
+/// Response of GetCapture
+///
+/// Returns a max of 1024 bytes of capture file.
+/// GetCapture will be returning a stream of GetCaptureResponse
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.frontend.GetCaptureResponse)
pub struct GetCaptureResponse {
// message fields
+ /// Max of 1024 bytes of capture file
// @@protoc_insertion_point(field:netsim.frontend.GetCaptureResponse.capture_stream)
pub capture_stream: ::std::vec::Vec<u8>,
// special fields
@@ -1854,7 +1907,169 @@ static file_descriptor_proto_data: &'static [u8] = b"\
reRequest\x1a\x16.google.protobuf.Empty\x12K\n\x0bListCapture\x12\x16.go\
ogle.protobuf.Empty\x1a$.netsim.frontend.ListCaptureResponse\x12W\n\nGet\
Capture\x12\".netsim.frontend.GetCaptureRequest\x1a#.netsim.frontend.Get\
- CaptureResponse0\x01b\x06proto3\
+ CaptureResponse0\x01J\xdc)\n\x07\x12\x05\x0e\0\xb3\x01\x01\n\xd2\x04\n\
+ \x01\x0c\x12\x03\x0e\0\x122\xc7\x04\x20Copyright\x202022\x20The\x20Andro\
+ id\x20Open\x20Source\x20Project\n\n\x20Licensed\x20under\x20the\x20Apach\
+ e\x20License,\x20Version\x202.0\x20(the\x20\"License\");\n\x20you\x20may\
+ \x20not\x20use\x20this\x20file\x20except\x20in\x20compliance\x20with\x20\
+ the\x20License.\n\x20You\x20may\x20obtain\x20a\x20copy\x20of\x20the\x20L\
+ icense\x20at\n\n\x20\x20\x20\x20\x20\x20http://www.apache.org/licenses/L\
+ ICENSE-2.0\n\n\x20Unless\x20required\x20by\x20applicable\x20law\x20or\
+ \x20agreed\x20to\x20in\x20writing,\x20software\n\x20distributed\x20under\
+ \x20the\x20License\x20is\x20distributed\x20on\x20an\x20\"AS\x20IS\"\x20B\
+ ASIS,\n\x20WITHOUT\x20WARRANTIES\x20OR\x20CONDITIONS\x20OF\x20ANY\x20KIN\
+ D,\x20either\x20express\x20or\x20implied.\n\x20See\x20the\x20License\x20\
+ for\x20the\x20specific\x20language\x20governing\x20permissions\x20and\n\
+ \x20limitations\x20under\x20the\x20License.\n\n\x08\n\x01\x02\x12\x03\
+ \x10\0\x18\n\t\n\x02\x03\0\x12\x03\x12\0%\n\t\n\x02\x03\x01\x12\x03\x13\
+ \0)\n\t\n\x02\x03\x02\x12\x03\x14\0\x1c\n\xe2\x02\n\x02\x06\0\x12\x04!\0\
+ B\x01\x1a\xd5\x02*\n\x20The\x20frontend\x20service\x20for\x20the\x20netw\
+ ork\x20simulator.\n\n\x20The\x20network\x20simulator\x20interconnects\
+ \x20virtual\x20radio\x20controllers\x20on\x20emulated\n\x20android\x20an\
+ d\x20accessory\x20devices\x20to\x20allows\x20control\x20of\x20the\x20top\
+ ology,\x20device\n\x20positions,\x20and\x20RF\x20characteristics.\n\n\
+ \x20Clients\x20of\x20the\x20frontend\x20service\x20include\x20a\x20Comma\
+ nd\x20Line\x20Interface\x20(cli),\x20Mobly\n\x20scripts,\x20and\x20a\x20\
+ web\x20UI.\n\n\n\n\n\x03\x06\0\x01\x12\x03!\x08\x17\n5\n\x04\x06\0\x02\0\
+ \x12\x03#\x02B\x1a(\x20Get\x20the\x20version\x20of\x20the\x20netsim\x20s\
+ ervice.\n\n\x0c\n\x05\x06\0\x02\0\x01\x12\x03#\x06\x10\n\x0c\n\x05\x06\0\
+ \x02\0\x02\x12\x03#\x11&\n\x0c\n\x05\x06\0\x02\0\x03\x12\x03#1@\n&\n\x04\
+ \x06\0\x02\x01\x12\x03&\x02G\x1a\x19\x20Create\x20a\x20builtin\x20device\
+ \n\n\x0c\n\x05\x06\0\x02\x01\x01\x12\x03&\x06\x12\n\x0c\n\x05\x06\0\x02\
+ \x01\x02\x12\x03&\x13&\n\x0c\n\x05\x06\0\x02\x01\x03\x12\x03&1E\nX\n\x04\
+ \x06\0\x02\x02\x12\x03)\x02D\x1aK\x20Delete\x20a\x20builtin\x20chip.\x20\
+ Implicitly\x20deletes\x20devices\x20which\x20contain\x20no\x20chips.\n\n\
+ \x0c\n\x05\x06\0\x02\x02\x01\x12\x03)\x06\x10\n\x0c\n\x05\x06\0\x02\x02\
+ \x02\x12\x03)\x11\"\n\x0c\n\x05\x06\0\x02\x02\x03\x12\x03)-B\n\x1d\n\x04\
+ \x06\0\x02\x03\x12\x03,\x02F\x1a\x10\x20Patch\x20a\x20device\n\n\x0c\n\
+ \x05\x06\0\x02\x03\x01\x12\x03,\x06\x11\n\x0c\n\x05\x06\0\x02\x03\x02\
+ \x12\x03,\x12$\n\x0c\n\x05\x06\0\x02\x03\x03\x12\x03,/D\n!\n\x04\x06\0\
+ \x02\x04\x12\x03/\x02C\x1a\x14\x20Reset\x20all\x20devices.\n\n\x0c\n\x05\
+ \x06\0\x02\x04\x01\x12\x03/\x06\x0b\n\x0c\n\x05\x06\0\x02\x04\x02\x12\
+ \x03/\x0c!\n\x0c\n\x05\x06\0\x02\x04\x03\x12\x03/,A\n$\n\x04\x06\0\x02\
+ \x05\x12\x032\x02E\x1a\x17\x20Get\x20a\x20list\x20of\x20devices\n\n\x0c\
+ \n\x05\x06\0\x02\x05\x01\x12\x032\x06\x10\n\x0c\n\x05\x06\0\x02\x05\x02\
+ \x12\x032\x11&\n\x0c\n\x05\x06\0\x02\x05\x03\x12\x0321C\n\xa4\x01\n\x04\
+ \x06\0\x02\x06\x12\x037\x02P\x1a\x96\x01\x20Get\x20a\x20list\x20of\x20de\
+ vices\x20when\x20a\x20device\x20event\x20is\x20published.\n\x20Waits\x20\
+ for\x20device\x20event\x20up\x20to\x2015\x20seconds\x20and\x20returns\
+ \x20Error\x20response\x20if\x20no\n\x20event\x20is\x20received\n\n\x0c\n\
+ \x05\x06\0\x02\x06\x01\x12\x037\x06\x15\n\x0c\n\x05\x06\0\x02\x06\x02\
+ \x12\x037\x16,\n\x0c\n\x05\x06\0\x02\x06\x03\x12\x0377N\nt\n\x04\x06\0\
+ \x02\x07\x12\x03;\x02H\x1ag\x20Patch\x20a\x20Capture\x20source\x20to\x20\
+ turn\x20capture\x20on/off.\n\x20When\x20turned\x20on\x20the\x20old\x20ca\
+ pture\x20contents\x20are\x20replaced.\n\n\x0c\n\x05\x06\0\x02\x07\x01\
+ \x12\x03;\x06\x12\n\x0c\n\x05\x06\0\x02\x07\x02\x12\x03;\x13&\n\x0c\n\
+ \x05\x06\0\x02\x07\x03\x12\x03;1F\n?\n\x04\x06\0\x02\x08\x12\x03>\x02G\
+ \x1a2\x20List\x20all\x20Captures\x20currently\x20connected\x20on\x20nets\
+ im.\n\n\x0c\n\x05\x06\0\x02\x08\x01\x12\x03>\x06\x11\n\x0c\n\x05\x06\0\
+ \x02\x08\x02\x12\x03>\x12'\n\x0c\n\x05\x06\0\x02\x08\x03\x12\x03>2E\nM\n\
+ \x04\x06\0\x02\t\x12\x03A\x02H\x1a@\x20Retrieve\x20the\x20contents\x20of\
+ \x20the\x20packet\x20capture\x20as\x20streaming\x20bytes\n\n\x0c\n\x05\
+ \x06\0\x02\t\x01\x12\x03A\x06\x10\n\x0c\n\x05\x06\0\x02\t\x02\x12\x03A\
+ \x11\"\n\x0c\n\x05\x06\0\x02\t\x06\x12\x03A-3\n\x0c\n\x05\x06\0\x02\t\
+ \x03\x12\x03A4F\nQ\n\x02\x04\0\x12\x04G\0J\x01\x1aE\x20Response\x20of\
+ \x20GetVersion.\n\n\x20Returns\x20the\x20version\x20of\x20the\x20netsim\
+ \x20service\n\n\n\n\x03\x04\0\x01\x12\x03G\x08\x17\n(\n\x04\x04\0\x02\0\
+ \x12\x03I\x02\x15\x1a\x1b\x20Version\x20of\x20netsim\x20service\n\n\x0c\
+ \n\x05\x04\0\x02\0\x05\x12\x03I\x02\x08\n\x0c\n\x05\x04\0\x02\0\x01\x12\
+ \x03I\t\x10\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03I\x13\x14\nX\n\x02\x04\
+ \x01\x12\x04O\0S\x01\x1aL\x20Request\x20of\x20CreateDevice.\n\n\x20Creat\
+ eDevice\x20is\x20only\x20used\x20for\x20built-in\x20devices.\n\n\n\n\x03\
+ \x04\x01\x01\x12\x03O\x08\x1b\nc\n\x04\x04\x01\x02\0\x12\x03R\x02'\x1aV\
+ \x20DeviceCreate\x20proto\x20for\x20creation.\x20Check\x20DeviceCreate\
+ \x20in\x20model.proto\x20for\x20more\n\x20detail.\n\n\x0c\n\x05\x04\x01\
+ \x02\0\x06\x12\x03R\x02\x1b\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03R\x1c\"\
+ \n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03R%&\nN\n\x02\x04\x02\x12\x04X\0[\
+ \x01\x1aB\x20Response\x20of\x20CreateDevice.\n\n\x20Returns\x20the\x20de\
+ vice\x20created\x20in\x20netsim\n\n\n\n\x03\x04\x02\x01\x12\x03X\x08\x1c\
+ \n\x1b\n\x04\x04\x02\x02\0\x12\x03Z\x02!\x1a\x0e\x20Device\x20proto\n\n\
+ \x0c\n\x05\x04\x02\x02\0\x06\x12\x03Z\x02\x15\n\x0c\n\x05\x04\x02\x02\0\
+ \x01\x12\x03Z\x16\x1c\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03Z\x1f\x20\nW\
+ \n\x02\x04\x03\x12\x04`\0c\x01\x1aK\x20Request\x20of\x20DeleteDevice.\n\
+ \n\x20DeleteDevice\x20is\x20only\x20used\x20for\x20built-in\x20device.\n\
+ \n\n\n\x03\x04\x03\x01\x12\x03`\x08\x19\n\x20\n\x04\x04\x03\x02\0\x12\
+ \x03b\x02\x10\x1a\x13\x20Device\x20Identifier\n\n\x0c\n\x05\x04\x03\x02\
+ \0\x05\x12\x03b\x02\x08\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03b\t\x0b\n\
+ \x0c\n\x05\x04\x03\x02\0\x03\x12\x03b\x0e\x0f\n\xb0\x01\n\x02\x04\x04\
+ \x12\x04i\0m\x01\x1a\xa3\x01\x20Request\x20of\x20PatchDevice.\n\n\x20You\
+ \x20may\x20patch\x20the\x20device\x20position,\x20orientation,\x20and\
+ \x20the\x20radio\x20states.\n\x20For\x20built-in\x20devices,\x20you\x20m\
+ ay\x20patch\x20the\x20specific\x20configurations.\n\n\n\n\x03\x04\x04\
+ \x01\x12\x03i\x08\x1a\nf\n\x04\x04\x04\x02\0\x12\x03l\x02!\x1aY\x20Devic\
+ e\x20proto.\x20You\x20must\x20include\x20either\x20the\x20id\x20or\x20na\
+ me\x20field\x20to\x20have\n\x20a\x20successful\x20patch.\n\n\x0c\n\x05\
+ \x04\x04\x02\0\x06\x12\x03l\x02\x15\n\x0c\n\x05\x04\x04\x02\0\x01\x12\
+ \x03l\x16\x1c\n\x0c\n\x05\x04\x04\x02\0\x03\x12\x03l\x1f\x20\n\x8a\x01\n\
+ \x02\x04\x05\x12\x04s\0z\x01\x1a~\x20Response\x20for\x20ListDevice\x20re\
+ quest.\n\n\x20Returns\x20the\x20emulators\x20and\x20accessory\x20devices\
+ \x20that\x20are\x20connected\x20to\n\x20the\x20network\x20simulator.\n\n\
+ \n\n\x03\x04\x05\x01\x12\x03s\x08\x1a\n$\n\x04\x04\x05\x02\0\x12\x03u\
+ \x02+\x1a\x17\x20List\x20of\x20Device\x20protos\n\n\x0c\n\x05\x04\x05\
+ \x02\0\x04\x12\x03u\x02\n\n\x0c\n\x05\x04\x05\x02\0\x06\x12\x03u\x0b\x1e\
+ \n\x0c\n\x05\x04\x05\x02\0\x01\x12\x03u\x1f&\n\x0c\n\x05\x04\x05\x02\0\
+ \x03\x12\x03u)*\n\x94\x01\n\x04\x04\x05\x02\x01\x12\x03y\x02.\x1a\x86\
+ \x01\x20Last\x20modified\x20timestamp\x20for\x20device\x20resource.\n\
+ \x20The\x20timestamp\x20will\x20be\x20updated\x20if\x20devices\x20state\
+ \x20has\x20changed\x20(except\x20for\n\x20packet\x20counts)\n\n\x0c\n\
+ \x05\x04\x05\x02\x01\x06\x12\x03y\x02\x1b\n\x0c\n\x05\x04\x05\x02\x01\
+ \x01\x12\x03y\x1c)\n\x0c\n\x05\x04\x05\x02\x01\x03\x12\x03y,-\n+\n\x02\
+ \x04\x06\x12\x05}\0\x82\x01\x01\x1a\x1e\x20Request\x20for\x20SubscribeDe\
+ vice.\n\n\n\n\x03\x04\x06\x01\x12\x03}\x08\x1e\n\xaa\x01\n\x04\x04\x06\
+ \x02\0\x12\x04\x81\x01\x027\x1a\x9b\x01\x20The\x20SubscribeDevice\x20wil\
+ l\x20immediately\x20return\x20if\x20the\n\x20provided\x20last_modified\
+ \x20timestamp\x20is\x20prior\x20to\x20the\x20current\x20last_modified\n\
+ \x20timestamp\x20in\x20device\x20resource.\n\n\r\n\x05\x04\x06\x02\0\x04\
+ \x12\x04\x81\x01\x02\n\n\r\n\x05\x04\x06\x02\0\x06\x12\x04\x81\x01\x0b$\
+ \n\r\n\x05\x04\x06\x02\0\x01\x12\x04\x81\x01%2\n\r\n\x05\x04\x06\x02\0\
+ \x03\x12\x04\x81\x0156\n5\n\x02\x04\x07\x12\x06\x85\x01\0\x8d\x01\x01\
+ \x1a'\x20Response\x20for\x20SubscribeDevice\x20request.\n\n\x0b\n\x03\
+ \x04\x07\x01\x12\x04\x85\x01\x08\x1f\nD\n\x04\x04\x07\x08\0\x12\x06\x87\
+ \x01\x02\x8c\x01\x03\x1a4\x20Will\x20return\x20ListDeviceResponse\x20or\
+ \x20an\x20EmptyResponse\n\n\r\n\x05\x04\x07\x08\0\x01\x12\x04\x87\x01\
+ \x08\x10\n'\n\x04\x04\x07\x02\0\x12\x04\x89\x01\x040\x1a\x19\x20Response\
+ \x20for\x20ListDevice\n\n\r\n\x05\x04\x07\x02\0\x06\x12\x04\x89\x01\x04\
+ \x16\n\r\n\x05\x04\x07\x02\0\x01\x12\x04\x89\x01\x17+\n\r\n\x05\x04\x07\
+ \x02\0\x03\x12\x04\x89\x01./\n\x1e\n\x04\x04\x07\x02\x01\x12\x04\x8b\x01\
+ \x04-\x1a\x10\x20Empty\x20Response\n\n\r\n\x05\x04\x07\x02\x01\x06\x12\
+ \x04\x8b\x01\x04\x19\n\r\n\x05\x04\x07\x02\x01\x01\x12\x04\x8b\x01\x1a(\
+ \n\r\n\x05\x04\x07\x02\x01\x03\x12\x04\x8b\x01+,\n(\n\x02\x04\x08\x12\
+ \x06\x90\x01\0\x9c\x01\x01\x1a\x1a\x20Request\x20of\x20PatchCapture.\n\n\
+ \x0b\n\x03\x04\x08\x01\x12\x04\x90\x01\x08\x1b\n\"\n\x04\x04\x08\x02\0\
+ \x12\x04\x92\x01\x02\x10\x1a\x14\x20Capture\x20Identifier\n\n\r\n\x05\
+ \x04\x08\x02\0\x05\x12\x04\x92\x01\x02\x08\n\r\n\x05\x04\x08\x02\0\x01\
+ \x12\x04\x92\x01\t\x0b\n\r\n\x05\x04\x08\x02\0\x03\x12\x04\x92\x01\x0e\
+ \x0f\n]\n\x04\x04\x08\x03\0\x12\x06\x96\x01\x02\x99\x01\x03\x1aM\x20Body\
+ \x20of\x20PatchCapture\x20that\x20will\x20be\x20channeled\x20into\n\x20b\
+ ody\x20for\x20HandleCaptureCxx\n\n\r\n\x05\x04\x08\x03\0\x01\x12\x04\x96\
+ \x01\n\x16\n\x1f\n\x06\x04\x08\x03\0\x02\0\x12\x04\x98\x01\x04!\x1a\x0f\
+ \x20Capture\x20state\n\n\x0f\n\x07\x04\x08\x03\0\x02\0\x06\x12\x04\x98\
+ \x01\x04\x16\n\x0f\n\x07\x04\x08\x03\0\x02\0\x01\x12\x04\x98\x01\x17\x1c\
+ \n\x0f\n\x07\x04\x08\x03\0\x02\0\x03\x12\x04\x98\x01\x1f\x20\n\"\n\x04\
+ \x04\x08\x02\x01\x12\x04\x9b\x01\x02\x19\x1a\x14\x20PatchCapture\x20prot\
+ o\n\n\r\n\x05\x04\x08\x02\x01\x06\x12\x04\x9b\x01\x02\x0e\n\r\n\x05\x04\
+ \x08\x02\x01\x01\x12\x04\x9b\x01\x0f\x14\n\r\n\x05\x04\x08\x02\x01\x03\
+ \x12\x04\x9b\x01\x17\x18\ni\n\x02\x04\t\x12\x06\xa1\x01\0\xa4\x01\x01\
+ \x1a[\x20Response\x20of\x20ListCapture\n\n\x20Returns\x20all\x20capture\
+ \x20information\x20of\x20devices\x20connected\x20to\x20netsim.\n\n\x0b\n\
+ \x03\x04\t\x01\x12\x04\xa1\x01\x08\x1b\n&\n\x04\x04\t\x02\0\x12\x04\xa3\
+ \x01\x02-\x1a\x18\x20List\x20of\x20Capture\x20protos\n\n\r\n\x05\x04\t\
+ \x02\0\x04\x12\x04\xa3\x01\x02\n\n\r\n\x05\x04\t\x02\0\x06\x12\x04\xa3\
+ \x01\x0b\x1f\n\r\n\x05\x04\t\x02\0\x01\x12\x04\xa3\x01\x20(\n\r\n\x05\
+ \x04\t\x02\0\x03\x12\x04\xa3\x01+,\n%\n\x02\x04\n\x12\x06\xa7\x01\0\xaa\
+ \x01\x01\x1a\x17\x20Request\x20of\x20GetCapture\n\n\x0b\n\x03\x04\n\x01\
+ \x12\x04\xa7\x01\x08\x19\n\"\n\x04\x04\n\x02\0\x12\x04\xa9\x01\x02\x10\
+ \x1a\x14\x20Capture\x20Identifier\n\n\r\n\x05\x04\n\x02\0\x05\x12\x04\
+ \xa9\x01\x02\x08\n\r\n\x05\x04\n\x02\0\x01\x12\x04\xa9\x01\t\x0b\n\r\n\
+ \x05\x04\n\x02\0\x03\x12\x04\xa9\x01\x0e\x0f\n\x93\x01\n\x02\x04\x0b\x12\
+ \x06\xb0\x01\0\xb3\x01\x01\x1a\x84\x01\x20Response\x20of\x20GetCapture\n\
+ \n\x20Returns\x20a\x20max\x20of\x201024\x20bytes\x20of\x20capture\x20fil\
+ e.\n\x20GetCapture\x20will\x20be\x20returning\x20a\x20stream\x20of\x20Ge\
+ tCaptureResponse\n\n\x0b\n\x03\x04\x0b\x01\x12\x04\xb0\x01\x08\x1a\n1\n\
+ \x04\x04\x0b\x02\0\x12\x04\xb2\x01\x02\x1b\x1a#\x20Max\x20of\x201024\x20\
+ bytes\x20of\x20capture\x20file\n\n\r\n\x05\x04\x0b\x02\0\x05\x12\x04\xb2\
+ \x01\x02\x07\n\r\n\x05\x04\x0b\x02\0\x01\x12\x04\xb2\x01\x08\x16\n\r\n\
+ \x05\x04\x0b\x02\0\x03\x12\x04\xb2\x01\x19\x1ab\x06proto3\
";
/// `FileDescriptorProto` object which was a source for this generated file
diff --git a/rust/proto/src/frontend_grpc.rs b/rust/proto/src/frontend_grpc.rs
new file mode 100644
index 0000000..f1e60ed
--- /dev/null
+++ b/rust/proto/src/frontend_grpc.rs
@@ -0,0 +1,558 @@
+// This file is generated. Do not edit
+// @generated
+
+// https://github.com/Manishearth/rust-clippy/issues/702
+#![allow(unknown_lints)]
+#![allow(clippy::all)]
+#![allow(box_pointers)]
+#![allow(dead_code)]
+#![allow(missing_docs)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(non_upper_case_globals)]
+#![allow(trivial_casts)]
+#![allow(unsafe_code)]
+#![allow(unused_imports)]
+#![allow(unused_results)]
+
+const METHOD_FRONTEND_SERVICE_GET_VERSION: ::grpcio::Method<
+ super::empty::Empty,
+ super::frontend::VersionResponse,
+> = ::grpcio::Method {
+ ty: ::grpcio::MethodType::Unary,
+ name: "/netsim.frontend.FrontendService/GetVersion",
+ req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+ resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+};
+
+const METHOD_FRONTEND_SERVICE_CREATE_DEVICE: ::grpcio::Method<
+ super::frontend::CreateDeviceRequest,
+ super::frontend::CreateDeviceResponse,
+> = ::grpcio::Method {
+ ty: ::grpcio::MethodType::Unary,
+ name: "/netsim.frontend.FrontendService/CreateDevice",
+ req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+ resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+};
+
+const METHOD_FRONTEND_SERVICE_DELETE_CHIP: ::grpcio::Method<
+ super::frontend::DeleteChipRequest,
+ super::empty::Empty,
+> = ::grpcio::Method {
+ ty: ::grpcio::MethodType::Unary,
+ name: "/netsim.frontend.FrontendService/DeleteChip",
+ req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+ resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+};
+
+const METHOD_FRONTEND_SERVICE_PATCH_DEVICE: ::grpcio::Method<
+ super::frontend::PatchDeviceRequest,
+ super::empty::Empty,
+> = ::grpcio::Method {
+ ty: ::grpcio::MethodType::Unary,
+ name: "/netsim.frontend.FrontendService/PatchDevice",
+ req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+ resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+};
+
+const METHOD_FRONTEND_SERVICE_RESET: ::grpcio::Method<super::empty::Empty, super::empty::Empty> =
+ ::grpcio::Method {
+ ty: ::grpcio::MethodType::Unary,
+ name: "/netsim.frontend.FrontendService/Reset",
+ req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+ resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+ };
+
+const METHOD_FRONTEND_SERVICE_LIST_DEVICE: ::grpcio::Method<
+ super::empty::Empty,
+ super::frontend::ListDeviceResponse,
+> = ::grpcio::Method {
+ ty: ::grpcio::MethodType::Unary,
+ name: "/netsim.frontend.FrontendService/ListDevice",
+ req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+ resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+};
+
+const METHOD_FRONTEND_SERVICE_SUBSCRIBE_DEVICE: ::grpcio::Method<
+ super::frontend::SubscribeDeviceRequest,
+ super::frontend::SubscribeDeviceResponse,
+> = ::grpcio::Method {
+ ty: ::grpcio::MethodType::Unary,
+ name: "/netsim.frontend.FrontendService/SubscribeDevice",
+ req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+ resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+};
+
+const METHOD_FRONTEND_SERVICE_PATCH_CAPTURE: ::grpcio::Method<
+ super::frontend::PatchCaptureRequest,
+ super::empty::Empty,
+> = ::grpcio::Method {
+ ty: ::grpcio::MethodType::Unary,
+ name: "/netsim.frontend.FrontendService/PatchCapture",
+ req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+ resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+};
+
+const METHOD_FRONTEND_SERVICE_LIST_CAPTURE: ::grpcio::Method<
+ super::empty::Empty,
+ super::frontend::ListCaptureResponse,
+> = ::grpcio::Method {
+ ty: ::grpcio::MethodType::Unary,
+ name: "/netsim.frontend.FrontendService/ListCapture",
+ req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+ resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+};
+
+const METHOD_FRONTEND_SERVICE_GET_CAPTURE: ::grpcio::Method<
+ super::frontend::GetCaptureRequest,
+ super::frontend::GetCaptureResponse,
+> = ::grpcio::Method {
+ ty: ::grpcio::MethodType::ServerStreaming,
+ name: "/netsim.frontend.FrontendService/GetCapture",
+ req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+ resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
+};
+
+#[derive(Clone)]
+pub struct FrontendServiceClient {
+ pub client: ::grpcio::Client,
+}
+
+impl FrontendServiceClient {
+ pub fn new(channel: ::grpcio::Channel) -> Self {
+ FrontendServiceClient { client: ::grpcio::Client::new(channel) }
+ }
+
+ pub fn get_version_opt(
+ &self,
+ req: &super::empty::Empty,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<super::frontend::VersionResponse> {
+ self.client.unary_call(&METHOD_FRONTEND_SERVICE_GET_VERSION, req, opt)
+ }
+
+ pub fn get_version(
+ &self,
+ req: &super::empty::Empty,
+ ) -> ::grpcio::Result<super::frontend::VersionResponse> {
+ self.get_version_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn get_version_async_opt(
+ &self,
+ req: &super::empty::Empty,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::frontend::VersionResponse>> {
+ self.client.unary_call_async(&METHOD_FRONTEND_SERVICE_GET_VERSION, req, opt)
+ }
+
+ pub fn get_version_async(
+ &self,
+ req: &super::empty::Empty,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::frontend::VersionResponse>> {
+ self.get_version_async_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn create_device_opt(
+ &self,
+ req: &super::frontend::CreateDeviceRequest,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<super::frontend::CreateDeviceResponse> {
+ self.client.unary_call(&METHOD_FRONTEND_SERVICE_CREATE_DEVICE, req, opt)
+ }
+
+ pub fn create_device(
+ &self,
+ req: &super::frontend::CreateDeviceRequest,
+ ) -> ::grpcio::Result<super::frontend::CreateDeviceResponse> {
+ self.create_device_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn create_device_async_opt(
+ &self,
+ req: &super::frontend::CreateDeviceRequest,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::frontend::CreateDeviceResponse>>
+ {
+ self.client.unary_call_async(&METHOD_FRONTEND_SERVICE_CREATE_DEVICE, req, opt)
+ }
+
+ pub fn create_device_async(
+ &self,
+ req: &super::frontend::CreateDeviceRequest,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::frontend::CreateDeviceResponse>>
+ {
+ self.create_device_async_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn delete_chip_opt(
+ &self,
+ req: &super::frontend::DeleteChipRequest,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<super::empty::Empty> {
+ self.client.unary_call(&METHOD_FRONTEND_SERVICE_DELETE_CHIP, req, opt)
+ }
+
+ pub fn delete_chip(
+ &self,
+ req: &super::frontend::DeleteChipRequest,
+ ) -> ::grpcio::Result<super::empty::Empty> {
+ self.delete_chip_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn delete_chip_async_opt(
+ &self,
+ req: &super::frontend::DeleteChipRequest,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::empty::Empty>> {
+ self.client.unary_call_async(&METHOD_FRONTEND_SERVICE_DELETE_CHIP, req, opt)
+ }
+
+ pub fn delete_chip_async(
+ &self,
+ req: &super::frontend::DeleteChipRequest,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::empty::Empty>> {
+ self.delete_chip_async_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn patch_device_opt(
+ &self,
+ req: &super::frontend::PatchDeviceRequest,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<super::empty::Empty> {
+ self.client.unary_call(&METHOD_FRONTEND_SERVICE_PATCH_DEVICE, req, opt)
+ }
+
+ pub fn patch_device(
+ &self,
+ req: &super::frontend::PatchDeviceRequest,
+ ) -> ::grpcio::Result<super::empty::Empty> {
+ self.patch_device_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn patch_device_async_opt(
+ &self,
+ req: &super::frontend::PatchDeviceRequest,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::empty::Empty>> {
+ self.client.unary_call_async(&METHOD_FRONTEND_SERVICE_PATCH_DEVICE, req, opt)
+ }
+
+ pub fn patch_device_async(
+ &self,
+ req: &super::frontend::PatchDeviceRequest,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::empty::Empty>> {
+ self.patch_device_async_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn reset_opt(
+ &self,
+ req: &super::empty::Empty,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<super::empty::Empty> {
+ self.client.unary_call(&METHOD_FRONTEND_SERVICE_RESET, req, opt)
+ }
+
+ pub fn reset(&self, req: &super::empty::Empty) -> ::grpcio::Result<super::empty::Empty> {
+ self.reset_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn reset_async_opt(
+ &self,
+ req: &super::empty::Empty,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::empty::Empty>> {
+ self.client.unary_call_async(&METHOD_FRONTEND_SERVICE_RESET, req, opt)
+ }
+
+ pub fn reset_async(
+ &self,
+ req: &super::empty::Empty,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::empty::Empty>> {
+ self.reset_async_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn list_device_opt(
+ &self,
+ req: &super::empty::Empty,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<super::frontend::ListDeviceResponse> {
+ self.client.unary_call(&METHOD_FRONTEND_SERVICE_LIST_DEVICE, req, opt)
+ }
+
+ pub fn list_device(
+ &self,
+ req: &super::empty::Empty,
+ ) -> ::grpcio::Result<super::frontend::ListDeviceResponse> {
+ self.list_device_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn list_device_async_opt(
+ &self,
+ req: &super::empty::Empty,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::frontend::ListDeviceResponse>> {
+ self.client.unary_call_async(&METHOD_FRONTEND_SERVICE_LIST_DEVICE, req, opt)
+ }
+
+ pub fn list_device_async(
+ &self,
+ req: &super::empty::Empty,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::frontend::ListDeviceResponse>> {
+ self.list_device_async_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn subscribe_device_opt(
+ &self,
+ req: &super::frontend::SubscribeDeviceRequest,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<super::frontend::SubscribeDeviceResponse> {
+ self.client.unary_call(&METHOD_FRONTEND_SERVICE_SUBSCRIBE_DEVICE, req, opt)
+ }
+
+ pub fn subscribe_device(
+ &self,
+ req: &super::frontend::SubscribeDeviceRequest,
+ ) -> ::grpcio::Result<super::frontend::SubscribeDeviceResponse> {
+ self.subscribe_device_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn subscribe_device_async_opt(
+ &self,
+ req: &super::frontend::SubscribeDeviceRequest,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::frontend::SubscribeDeviceResponse>>
+ {
+ self.client.unary_call_async(&METHOD_FRONTEND_SERVICE_SUBSCRIBE_DEVICE, req, opt)
+ }
+
+ pub fn subscribe_device_async(
+ &self,
+ req: &super::frontend::SubscribeDeviceRequest,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::frontend::SubscribeDeviceResponse>>
+ {
+ self.subscribe_device_async_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn patch_capture_opt(
+ &self,
+ req: &super::frontend::PatchCaptureRequest,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<super::empty::Empty> {
+ self.client.unary_call(&METHOD_FRONTEND_SERVICE_PATCH_CAPTURE, req, opt)
+ }
+
+ pub fn patch_capture(
+ &self,
+ req: &super::frontend::PatchCaptureRequest,
+ ) -> ::grpcio::Result<super::empty::Empty> {
+ self.patch_capture_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn patch_capture_async_opt(
+ &self,
+ req: &super::frontend::PatchCaptureRequest,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::empty::Empty>> {
+ self.client.unary_call_async(&METHOD_FRONTEND_SERVICE_PATCH_CAPTURE, req, opt)
+ }
+
+ pub fn patch_capture_async(
+ &self,
+ req: &super::frontend::PatchCaptureRequest,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::empty::Empty>> {
+ self.patch_capture_async_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn list_capture_opt(
+ &self,
+ req: &super::empty::Empty,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<super::frontend::ListCaptureResponse> {
+ self.client.unary_call(&METHOD_FRONTEND_SERVICE_LIST_CAPTURE, req, opt)
+ }
+
+ pub fn list_capture(
+ &self,
+ req: &super::empty::Empty,
+ ) -> ::grpcio::Result<super::frontend::ListCaptureResponse> {
+ self.list_capture_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn list_capture_async_opt(
+ &self,
+ req: &super::empty::Empty,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::frontend::ListCaptureResponse>> {
+ self.client.unary_call_async(&METHOD_FRONTEND_SERVICE_LIST_CAPTURE, req, opt)
+ }
+
+ pub fn list_capture_async(
+ &self,
+ req: &super::empty::Empty,
+ ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::frontend::ListCaptureResponse>> {
+ self.list_capture_async_opt(req, ::grpcio::CallOption::default())
+ }
+
+ pub fn get_capture_opt(
+ &self,
+ req: &super::frontend::GetCaptureRequest,
+ opt: ::grpcio::CallOption,
+ ) -> ::grpcio::Result<::grpcio::ClientSStreamReceiver<super::frontend::GetCaptureResponse>>
+ {
+ self.client.server_streaming(&METHOD_FRONTEND_SERVICE_GET_CAPTURE, req, opt)
+ }
+
+ pub fn get_capture(
+ &self,
+ req: &super::frontend::GetCaptureRequest,
+ ) -> ::grpcio::Result<::grpcio::ClientSStreamReceiver<super::frontend::GetCaptureResponse>>
+ {
+ self.get_capture_opt(req, ::grpcio::CallOption::default())
+ }
+ pub fn spawn<F>(&self, f: F)
+ where
+ F: ::std::future::Future<Output = ()> + Send + 'static,
+ {
+ self.client.spawn(f)
+ }
+}
+
+pub trait FrontendService {
+ fn get_version(
+ &mut self,
+ ctx: ::grpcio::RpcContext,
+ _req: super::empty::Empty,
+ sink: ::grpcio::UnarySink<super::frontend::VersionResponse>,
+ ) {
+ grpcio::unimplemented_call!(ctx, sink)
+ }
+ fn create_device(
+ &mut self,
+ ctx: ::grpcio::RpcContext,
+ _req: super::frontend::CreateDeviceRequest,
+ sink: ::grpcio::UnarySink<super::frontend::CreateDeviceResponse>,
+ ) {
+ grpcio::unimplemented_call!(ctx, sink)
+ }
+ fn delete_chip(
+ &mut self,
+ ctx: ::grpcio::RpcContext,
+ _req: super::frontend::DeleteChipRequest,
+ sink: ::grpcio::UnarySink<super::empty::Empty>,
+ ) {
+ grpcio::unimplemented_call!(ctx, sink)
+ }
+ fn patch_device(
+ &mut self,
+ ctx: ::grpcio::RpcContext,
+ _req: super::frontend::PatchDeviceRequest,
+ sink: ::grpcio::UnarySink<super::empty::Empty>,
+ ) {
+ grpcio::unimplemented_call!(ctx, sink)
+ }
+ fn reset(
+ &mut self,
+ ctx: ::grpcio::RpcContext,
+ _req: super::empty::Empty,
+ sink: ::grpcio::UnarySink<super::empty::Empty>,
+ ) {
+ grpcio::unimplemented_call!(ctx, sink)
+ }
+ fn list_device(
+ &mut self,
+ ctx: ::grpcio::RpcContext,
+ _req: super::empty::Empty,
+ sink: ::grpcio::UnarySink<super::frontend::ListDeviceResponse>,
+ ) {
+ grpcio::unimplemented_call!(ctx, sink)
+ }
+ fn subscribe_device(
+ &mut self,
+ ctx: ::grpcio::RpcContext,
+ _req: super::frontend::SubscribeDeviceRequest,
+ sink: ::grpcio::UnarySink<super::frontend::SubscribeDeviceResponse>,
+ ) {
+ grpcio::unimplemented_call!(ctx, sink)
+ }
+ fn patch_capture(
+ &mut self,
+ ctx: ::grpcio::RpcContext,
+ _req: super::frontend::PatchCaptureRequest,
+ sink: ::grpcio::UnarySink<super::empty::Empty>,
+ ) {
+ grpcio::unimplemented_call!(ctx, sink)
+ }
+ fn list_capture(
+ &mut self,
+ ctx: ::grpcio::RpcContext,
+ _req: super::empty::Empty,
+ sink: ::grpcio::UnarySink<super::frontend::ListCaptureResponse>,
+ ) {
+ grpcio::unimplemented_call!(ctx, sink)
+ }
+ fn get_capture(
+ &mut self,
+ ctx: ::grpcio::RpcContext,
+ _req: super::frontend::GetCaptureRequest,
+ sink: ::grpcio::ServerStreamingSink<super::frontend::GetCaptureResponse>,
+ ) {
+ grpcio::unimplemented_call!(ctx, sink)
+ }
+}
+
+pub fn create_frontend_service<S: FrontendService + Send + Clone + 'static>(
+ s: S,
+) -> ::grpcio::Service {
+ let mut builder = ::grpcio::ServiceBuilder::new();
+ let mut instance = s.clone();
+ builder = builder
+ .add_unary_handler(&METHOD_FRONTEND_SERVICE_GET_VERSION, move |ctx, req, resp| {
+ instance.get_version(ctx, req, resp)
+ });
+ let mut instance = s.clone();
+ builder = builder
+ .add_unary_handler(&METHOD_FRONTEND_SERVICE_CREATE_DEVICE, move |ctx, req, resp| {
+ instance.create_device(ctx, req, resp)
+ });
+ let mut instance = s.clone();
+ builder = builder
+ .add_unary_handler(&METHOD_FRONTEND_SERVICE_DELETE_CHIP, move |ctx, req, resp| {
+ instance.delete_chip(ctx, req, resp)
+ });
+ let mut instance = s.clone();
+ builder = builder
+ .add_unary_handler(&METHOD_FRONTEND_SERVICE_PATCH_DEVICE, move |ctx, req, resp| {
+ instance.patch_device(ctx, req, resp)
+ });
+ let mut instance = s.clone();
+ builder = builder.add_unary_handler(&METHOD_FRONTEND_SERVICE_RESET, move |ctx, req, resp| {
+ instance.reset(ctx, req, resp)
+ });
+ let mut instance = s.clone();
+ builder = builder
+ .add_unary_handler(&METHOD_FRONTEND_SERVICE_LIST_DEVICE, move |ctx, req, resp| {
+ instance.list_device(ctx, req, resp)
+ });
+ let mut instance = s.clone();
+ builder = builder
+ .add_unary_handler(&METHOD_FRONTEND_SERVICE_SUBSCRIBE_DEVICE, move |ctx, req, resp| {
+ instance.subscribe_device(ctx, req, resp)
+ });
+ let mut instance = s.clone();
+ builder = builder
+ .add_unary_handler(&METHOD_FRONTEND_SERVICE_PATCH_CAPTURE, move |ctx, req, resp| {
+ instance.patch_capture(ctx, req, resp)
+ });
+ let mut instance = s.clone();
+ builder = builder
+ .add_unary_handler(&METHOD_FRONTEND_SERVICE_LIST_CAPTURE, move |ctx, req, resp| {
+ instance.list_capture(ctx, req, resp)
+ });
+ let mut instance = s;
+ builder = builder.add_server_streaming_handler(
+ &METHOD_FRONTEND_SERVICE_GET_CAPTURE,
+ move |ctx, req, resp| instance.get_capture(ctx, req, resp),
+ );
+ builder.build()
+}
diff --git a/rust/proto/src/lib.rs b/rust/proto/src/lib.rs
index c9eb9ec..8397ff6 100644
--- a/rust/proto/src/lib.rs
+++ b/rust/proto/src/lib.rs
@@ -14,11 +14,16 @@
// limitations under the License.
//! protobuf library for netsim
+#[cfg(feature = "cuttlefish")]
+use protobuf::well_known_types::empty;
pub mod common;
pub mod config;
pub mod configuration;
pub mod frontend;
+// TODO: Remove feature check once crate dependency is resolved
+#[cfg(feature = "cuttlefish")]
+pub mod frontend_grpc;
pub mod hci_packet;
pub mod model;
pub mod packet_streamer;
diff --git a/scripts/build_tools.py b/scripts/build_tools.py
index e8f5db0..acb00a4 100755
--- a/scripts/build_tools.py
+++ b/scripts/build_tools.py
@@ -85,7 +85,8 @@ def main():
args.out_dir = os.path.join(AOSP_ROOT, args.out_dir)
out = Path(args.out_dir)
- shutil.rmtree(out)
+ if out.exists():
+ shutil.rmtree(out)
out.mkdir(exist_ok=True, parents=True)
@@ -119,8 +120,8 @@ def main():
with ServerConfig(presubmit, args) as cfg:
# Turn on sccache?
- if cfg.sccache:
- launcher.append(f"-DOPTION_CCACHE=${cfg.sccache}")
+ #if cfg.sccache:
+ # launcher.append(f"-DOPTION_CCACHE=${cfg.sccache}")
# Configure
run(launcher, cfg.get_env(), "bld")
diff --git a/scripts/proto_update.sh b/scripts/proto_update.sh
index 1062b91..6353465 100755
--- a/scripts/proto_update.sh
+++ b/scripts/proto_update.sh
@@ -40,6 +40,13 @@ export CARGO_HOME=$REPO/objs/rust/.cargo
cd $REPO
cargo build --manifest-path $CARGO
+# run protoc command to generate grpc proto rust files
+# Possibly need to install compilers:
+# $ cargo install protobuf-codegen
+# $ cargo install grpcio-compiler
+# TODO: Need to add required crate mappings to work in emu-master-dev
+# protoc --rust_out=./rust/proto/src --grpc_out=./rust/proto/src --plugin=protoc-gen-grpc=`which grpc_rust_plugin` -I./proto -I../../external/protobuf/src -I../../packages/modules/Bluetooth/tools/rootcanal/proto ./proto/netsim/frontend.proto
+
# Undo changed to Cargo.toml
git checkout $CARGO
diff --git a/scripts/utils.py b/scripts/utils.py
index 4bf6124..8809fc7 100644
--- a/scripts/utils.py
+++ b/scripts/utils.py
@@ -40,9 +40,11 @@ TARGET_MAP = {
"windows_x64": "windows_msvc-x86_64",
"linux": "linux-x86_64",
"linux_x64": "linux-x86_64",
+ "linux_x86_64": "linux-x86_64",
+ "linux_aarch64": "linux-aarch64",
"darwin": "darwin-x86_64",
"darwin_x64": "darwin-x86_64",
- "linux_aarch64": "linux-aarch64",
+ "darwin_x86_64" : "darwin-x86_64",
"darwin_aarch64": "darwin-aarch64",
}
@@ -57,7 +59,7 @@ AVAILABLE = {
def platform_to_cmake_target(target):
"""Translates platform to cmake target"""
- return TARGET_MAP[target]
+ return TARGET_MAP[target.replace("-","_")]
def cmake_toolchain(target) -> str:
@@ -69,7 +71,7 @@ def cmake_toolchain(target) -> str:
/ "android"
/ "build"
/ "cmake"
- / AVAILABLE[TARGET_MAP[target]]
+ / AVAILABLE[TARGET_MAP[target.replace("-", "_")]]
)