diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-17 02:16:24 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-17 02:16:24 +0000 |
commit | 3417cf89494be9900c2a4d0ab9a70386e25c0bfa (patch) | |
tree | c183e84d46d6b3fca2929cadaa058d22738ac109 | |
parent | c8ec243e9a5ab980573c72b44d6b9bbdd8b44569 (diff) | |
parent | a476e3bfdc11d50e47098682b7490970115f6b11 (diff) | |
download | netsim-3417cf89494be9900c2a4d0ab9a70386e25c0bfa.tar.gz |
Snap for 11228863 from a476e3bfdc11d50e47098682b7490970115f6b11 to emu-34-release
Change-Id: Ifd0669072c137732cafc376404791038fc864f00
35 files changed, 1149 insertions, 453 deletions
@@ -53,10 +53,6 @@ cc_defaults { generated_sources: [ "FrontendStub_cc", ], - include_dirs: [ - "bionic/libc/kernel/uapi/", - "bionic/libc/kernel/android/uapi/", - ], } rust_defaults { diff --git a/TEST_MAPPING b/TEST_MAPPING new file mode 100644 index 0000000..7842629 --- /dev/null +++ b/TEST_MAPPING @@ -0,0 +1,16 @@ +{ + "presubmit": [ + { + "name": "CtsBluetoothTestCases", + "options": [ + { + // TODO(b/303306195): Exclude a flaky test the other team is already working on from our check + "exclude-filter": "android.bluetooth.cts.LeL2capSocketTest#openInsecureLeL2capServerSocketRepeatedly" + } + ] + }, + { + "name": "net_test_bluetooth" + } + ] +}
\ No newline at end of file diff --git a/pdl/ieee80211.pdl b/pdl/ieee80211.pdl index f94a6b2..3e28f60 100644 --- a/pdl/ieee80211.pdl +++ b/pdl/ieee80211.pdl @@ -5,6 +5,8 @@ little_endian_packets +custom_field MacAddress : 48 "macaddr/" + // Frame type B3..B2 enum FrameType : 2 { MGMT = 0, @@ -13,7 +15,21 @@ enum FrameType : 2 { EXT = 3, } -// Management subtype B7..B4 +// Data substypes +enum DataSubType : 4 { + DATA = 0, + DATA_CF_ACK = 1, + DATA_CF_POLL = 2, + DATA_CF_ACPL = 3, + NODATA = 4, + NODATA_CF_ACK = 5, + NODATA_CF_POLL = 6, + NODATA_CF_ACPL = 7, + QOS = 8, + QOS_NULL = 12, +} + +// Management subtypes enum ManagementSubType : 4 { ASSOC_REQ = 0, ASSOC_RESP = 1, @@ -29,12 +45,12 @@ enum ManagementSubType : 4 { ACTION = 13, } -struct FrameControl { +group FrameControl { version : 2, // B1..B0 ftype: FrameType, // B3..B2 stype: 4, // B7..B4 - tods: 1, // B8 - fromds: 1, // B9 + to_ds: 1, // B8 + from_ds: 1, // B9 more_frags: 1, // B10 retry: 1, // B11 pm : 1, // B12 @@ -43,13 +59,58 @@ struct FrameControl { order: 1, // B15 } + packet Ieee80211 { - frame_control: FrameControl, + FrameControl, duration_id: 16, - addr1 : 8[6], - addr2 : 8[6], - addr3 : 8[6], + _payload_, +} + +/* + * DS bit usage + * + * TA = transmitter address + * RA = receiver address + * DA = destination address + * SA = source address + * + * ToDS FromDS A1(RA) A2(TA) A3 A4 Use + * ----------------------------------------------------------------- + * 0 0 DA SA BSSID - IBSS/DLS + * 0 1 DA BSSID SA - AP -> STA + * 1 0 BSSID SA DA - AP <- STA + * 1 1 RA TA DA SA unspecified (WDS) + */ + +packet Ieee80211Ibss : Ieee80211 (to_ds=0, from_ds=0) { + destination : MacAddress, + source : MacAddress, + bssid : MacAddress, + seq_ctrl : 16, + payload: 8[], +} + +packet Ieee80211FromAp : Ieee80211 (to_ds=0, from_ds=1) { + destination : MacAddress, + bssid : MacAddress, + source : MacAddress, + seq_ctrl : 16, + payload: 8[], +} + +packet Ieee80211ToAp : Ieee80211 (to_ds=1, from_ds=0) { + bssid : MacAddress, + source : MacAddress, + destination : MacAddress, + seq_ctrl : 16, + payload: 8[], +} + +packet Ieee80211Wds : Ieee80211 (to_ds=1, from_ds=1) { + receiver : MacAddress, + transmitter : MacAddress, + destination : MacAddress, seq_ctrl : 16, - addr4 : 8[6], + source : MacAddress, payload: 8[], } diff --git a/proto/netsim/config.proto b/proto/netsim/config.proto index cb27ba1..e48ba87 100644 --- a/proto/netsim/config.proto +++ b/proto/netsim/config.proto @@ -54,11 +54,19 @@ message WiFi { message Bluetooth { optional rootcanal.configuration.Controller properties = 1; - optional bool address_reuse = 2; + // default is False + optional bool disable_address_reuse = 2; + // default is False + optional bool test_beacons = 3; +} + +message Capture { + optional bool enabled = 1; } message Config { // Major sections Bluetooth bluetooth = 1; WiFi wifi = 2; -}
\ No newline at end of file + Capture capture = 3; +} diff --git a/rust/cli/Cargo.toml b/rust/cli/Cargo.toml index 553c8a8..3df2f83 100644 --- a/rust/cli/Cargo.toml +++ b/rust/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "netsim-cli" -version = "0.2.2" +version = "0.2.3" edition = "2021" build = "build.rs" diff --git a/rust/daemon/Cargo.toml b/rust/daemon/Cargo.toml index dc490b4..6b970dd 100644 --- a/rust/daemon/Cargo.toml +++ b/rust/daemon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "netsim-daemon" -version = "0.2.2" +version = "0.2.3" edition = "2021" build = "build.rs" diff --git a/rust/daemon/src/bluetooth/beacon.rs b/rust/daemon/src/bluetooth/beacon.rs index 13d8ef8..77c6964 100644 --- a/rust/daemon/src/bluetooth/beacon.rs +++ b/rust/daemon/src/bluetooth/beacon.rs @@ -234,7 +234,6 @@ impl RustBluetoothChipCallbacks for BeaconChipCallbacks { /// Similar to `bluetooth_add()`. #[cfg(not(test))] pub fn ble_beacon_add( - device_id: DeviceIdentifier, device_name: String, chip_id: ChipIdentifier, chip_proto: &ChipCreateProto, @@ -253,17 +252,14 @@ pub fn ble_beacon_add( let callbacks: Box<dyn RustBluetoothChipCallbacks> = Box::new(BeaconChipCallbacks { chip_id }); let add_rust_device_result = rust_bluetooth_add( - device_id, + chip_id, callbacks, String::from("beacon"), beacon_proto.address.clone(), ); let rust_chip = add_rust_device_result.rust_chip; let facade_id = add_rust_device_result.facade_id; - info!( - "Creating HCI facade_id: {} for device_id: {} chip_id: {}", - facade_id, device_id, chip_id - ); + info!("Creating HCI facade_id: {} for chip_id: {}", facade_id, chip_id); BT_CHIPS.write().unwrap().insert(chip_id, Mutex::new(rust_chip)); Ok(facade_id) @@ -408,6 +404,7 @@ pub mod tests { }; use super::*; + // using ble_beacon_add from mocked.rs use crate::bluetooth::ble_beacon_add; lazy_static! { @@ -418,7 +415,6 @@ pub mod tests { let id = TEST_GUID_GENERATOR.lock().unwrap().next_id(); let add_result = ble_beacon_add( - 0, format!("test-device-{:?}", thread::current().id()), id, &ChipCreateProto { diff --git a/rust/daemon/src/bluetooth/chip.rs b/rust/daemon/src/bluetooth/chip.rs index faaecbe..add0a86 100644 --- a/rust/daemon/src/bluetooth/chip.rs +++ b/rust/daemon/src/bluetooth/chip.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::ffi::ffi_bluetooth::RustBluetoothChip; +use crate::{devices::chip::ChipIdentifier, ffi::ffi_bluetooth::RustBluetoothChip}; use cxx::{let_cxx_string, UniquePtr}; /// Rust bluetooth chip trait. @@ -44,7 +44,7 @@ pub fn create_add_rust_device_result( /// Add a bluetooth chip by an object implements RustBluetoothChipCallbacks trait. pub fn rust_bluetooth_add( - device_id: u32, + chip_id: ChipIdentifier, callbacks: Box<dyn RustBluetoothChipCallbacks>, string_type: String, address: String, @@ -52,7 +52,7 @@ pub fn rust_bluetooth_add( let_cxx_string!(cxx_string_type = string_type); let_cxx_string!(cxx_address = address); crate::ffi::ffi_bluetooth::bluetooth_add_rust_device( - device_id, + chip_id, Box::new(callbacks), &cxx_string_type, &cxx_address, diff --git a/rust/daemon/src/bluetooth/mocked.rs b/rust/daemon/src/bluetooth/mocked.rs index 41e757a..68a60a6 100644 --- a/rust/daemon/src/bluetooth/mocked.rs +++ b/rust/daemon/src/bluetooth/mocked.rs @@ -43,7 +43,6 @@ impl FacadeIds { // Avoid crossing cxx boundary in tests pub fn ble_beacon_add( - device_id: DeviceIdentifier, device_name: String, chip_id: ChipIdentifier, chip_proto: &ChipCreate, diff --git a/rust/daemon/src/captures/capture.rs b/rust/daemon/src/captures/capture.rs index f692f15..3770418 100644 --- a/rust/daemon/src/captures/capture.rs +++ b/rust/daemon/src/captures/capture.rs @@ -19,7 +19,7 @@ //! ChipIdentifier and <FacadeIdentifier, Kind> to CaptureInfo. use std::collections::btree_map::{Iter, Values}; -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; use std::fs::{File, OpenOptions}; use std::io::{Error, ErrorKind, Result}; use std::sync::mpsc::Receiver; @@ -37,15 +37,13 @@ use netsim_proto::{ use protobuf::well_known_types::timestamp::Timestamp; use crate::config::get_pcap; -use crate::events::Event; +use crate::events::{ChipAdded, ChipRemoved, Event}; use crate::resource::clone_captures; use crate::devices::chip::ChipIdentifier; -use crate::devices::chip::FacadeIdentifier; /// Internal Capture struct pub struct CaptureInfo { - facade_id: FacadeIdentifier, /// Some(File) if the file is opened and capture is actively happening. /// None if the file is not opened. pub file: Option<File>, @@ -71,11 +69,7 @@ pub struct CaptureInfo { /// and owning device name. /// /// Information for any recent or ongoing captures is also stored in the ProtoCapture. -/// facade_key_to_capture allows for fast lookups when handle_request, handle_response -/// is invoked from packet_hub. pub struct Captures { - /// A mapping of (chip kind, facade id) to CaptureInfo. - pub facade_key_to_capture: HashMap<(ChipKind, FacadeIdentifier), Arc<Mutex<CaptureInfo>>>, /// A mapping of chip id to CaptureInfo. /// /// BTreeMap is used for chip_id_to_capture, so that the CaptureInfo can always be @@ -85,14 +79,8 @@ pub struct Captures { impl CaptureInfo { /// Create an instance of CaptureInfo - pub fn new( - chip_kind: ChipKind, - facade_id: FacadeIdentifier, - chip_id: ChipIdentifier, - device_name: String, - ) -> Self { + pub fn new(chip_kind: ChipKind, chip_id: ChipIdentifier, device_name: String) -> Self { CaptureInfo { - facade_id, id: chip_id, chip_kind, device_name, @@ -141,20 +129,6 @@ impl CaptureInfo { self.file = None; } - /// A static helper function that returns facade_key from chip kind and facade id. - /// - /// This key will be used for facade_key_to_capture. - pub fn new_facade_key( - kind: ChipKind, - facade_id: FacadeIdentifier, - ) -> (ChipKind, FacadeIdentifier) { - (kind, facade_id) - } - - fn get_facade_key(&self) -> (ChipKind, FacadeIdentifier) { - CaptureInfo::new_facade_key(self.chip_kind, self.facade_id) - } - /// Returns a Capture protobuf from CaptureInfo pub fn get_capture_proto(&self) -> ProtoCapture { let timestamp = @@ -179,11 +153,7 @@ impl CaptureInfo { impl Captures { /// Create an instance of Captures, which includes 2 empty hashmaps pub fn new() -> Self { - Captures { - facade_key_to_capture: - HashMap::<(ChipKind, FacadeIdentifier), Arc<Mutex<CaptureInfo>>>::new(), - chip_id_to_capture: BTreeMap::<ChipIdentifier, Arc<Mutex<CaptureInfo>>>::new(), - } + Captures { chip_id_to_capture: BTreeMap::<ChipIdentifier, Arc<Mutex<CaptureInfo>>>::new() } } /// Returns true if key exists in Captures.chip_id_to_capture @@ -199,10 +169,8 @@ impl Captures { /// Inserts the given CatpureInfo into Captures hashmaps pub fn insert(&mut self, capture: CaptureInfo) { let chip_id = capture.id; - let facade_key = capture.get_facade_key(); let arc_capture = Arc::new(Mutex::new(capture)); self.chip_id_to_capture.insert(chip_id, arc_capture.clone()); - self.facade_key_to_capture.insert(facade_key, arc_capture); } /// Returns true if chip_id_to_capture is empty @@ -249,24 +217,23 @@ impl Default for Captures { /// and ChipRemoved events and updates the collection of CaptureInfo. /// pub fn spawn_capture_event_subscriber(event_rx: Receiver<Event>) { - let _ = thread::Builder::new().name("capture_event_subscriber".to_string()).spawn(move || { - loop { + let _ = + thread::Builder::new().name("capture_event_subscriber".to_string()).spawn(move || loop { match event_rx.recv() { - Ok(Event::ChipAdded { chip_id, chip_kind, facade_id, device_name, .. }) => { + Ok(Event::ChipAdded(ChipAdded { chip_id, chip_kind, device_name, .. })) => { let mut capture_info = - CaptureInfo::new(chip_kind, facade_id, chip_id, device_name.clone()); + CaptureInfo::new(chip_kind, chip_id, device_name.clone()); if get_pcap() { let _ = capture_info.start_capture(); } clone_captures().write().unwrap().insert(capture_info); - info!("Capture event: ChipAdded chip_id: {chip_id} device_name: {device_name} facade_id:{facade_id}"); + info!("Capture event: ChipAdded chip_id: {chip_id} device_name: {device_name}"); } - Ok(Event::ChipRemoved { chip_id, .. }) => { + Ok(Event::ChipRemoved(ChipRemoved { chip_id, .. })) => { clone_captures().write().unwrap().remove(&chip_id); info!("Capture event: ChipRemoved chip_id: {chip_id}"); } _ => {} } - } - }); + }); } diff --git a/rust/daemon/src/devices/chip.rs b/rust/daemon/src/devices/chip.rs index 7e00196..2008257 100644 --- a/rust/daemon/src/devices/chip.rs +++ b/rust/daemon/src/devices/chip.rs @@ -26,18 +26,35 @@ use netsim_proto::configuration::Controller as ProtoController; use netsim_proto::model::Chip as ProtoChip; use netsim_proto::stats::NetsimRadioStats as ProtoRadioStats; use protobuf::EnumOrUnknown; -use std::sync::RwLock; +use std::collections::HashMap; +use std::sync::{Arc, Mutex, MutexGuard, RwLock}; use std::time::Instant; +use super::device::DeviceIdentifier; + pub type ChipIdentifier = u32; pub type FacadeIdentifier = u32; const INITIAL_CHIP_ID: ChipIdentifier = 1000; +// ChipMap is a singleton that contains a hash map from +// chip_id to Chip objects. +type ChipMap = HashMap<ChipIdentifier, Chip>; + +#[derive(Clone)] +struct SharedChips(Arc<Mutex<ChipMap>>); + +impl SharedChips { + fn lock(&self) -> MutexGuard<ChipMap> { + self.0.lock().expect("Poisoned Shared Chips lock") + } +} + // Allocator for chip identifiers. lazy_static! { static ref IDS: RwLock<IdFactory<ChipIdentifier>> = RwLock::new(IdFactory::new(INITIAL_CHIP_ID, 1)); + static ref CHIPS: SharedChips = SharedChips(Arc::new(Mutex::new(HashMap::new()))); } pub struct CreateParams { @@ -51,8 +68,10 @@ pub struct CreateParams { /// Chip contains the common information for each Chip/Controller. /// Radio-specific information is contained in the emulated_chip. +#[derive(Clone)] pub struct Chip { pub id: ChipIdentifier, + pub device_id: DeviceIdentifier, pub emulated_chip: Option<SharedEmulatedChip>, pub kind: ProtoChipKind, pub address: String, @@ -71,9 +90,15 @@ impl Chip { // Any Chip with an emulated_chip == None is temporary. // Creating the echip first required holding a Chip+Device lock through // initialization which caused a deadlock under certain (rare) conditions. - fn new(id: ChipIdentifier, device_name: &str, create_params: &CreateParams) -> Self { + fn new( + id: ChipIdentifier, + device_id: DeviceIdentifier, + device_name: &str, + create_params: &CreateParams, + ) -> Self { Self { id, + device_id, emulated_chip: None, kind: create_params.kind, address: create_params.address.clone(), @@ -92,7 +117,7 @@ impl Chip { // stats for BLE and CLASSIC. pub fn get_stats(&self) -> Vec<ProtoRadioStats> { match &self.emulated_chip { - Some(emulated_chip) => emulated_chip.get_stats(self.start.elapsed().as_secs()), + Some(emulated_chip) => emulated_chip.lock().get_stats(self.start.elapsed().as_secs()), None => { warn!("EmulatedChip hasn't been instantiated yet for chip_id {}", self.id); Vec::<ProtoRadioStats>::new() @@ -105,7 +130,7 @@ impl Chip { let mut proto_chip = self .emulated_chip .as_ref() - .map(|c| c.get()) + .map(|c| c.lock().get()) .ok_or(format!("EmulatedChip hasn't been instantiated yet for chip_id {}", self.id))?; proto_chip.kind = EnumOrUnknown::new(self.kind); proto_chip.id = self.id; @@ -126,20 +151,186 @@ impl Chip { } self.emulated_chip .as_ref() - .map(|c| c.patch(patch)) + .map(|c| c.lock().patch(patch)) .ok_or(format!("EmulatedChip hasn't been instantiated yet for chip_id {}", self.id)) } pub fn reset(&mut self) -> Result<(), String> { self.emulated_chip .as_ref() - .map(|c| c.reset()) + .map(|c| c.lock().reset()) .ok_or(format!("EmulatedChip hasn't been instantiated yet for chip_id {}", self.id)) } } -/// Allocates a new chip with a facade_id. -pub fn chip_new(device_name: &str, create_params: &CreateParams) -> Result<Chip, String> { - let id = IDS.write().unwrap().next_id(); - Ok(Chip::new(id, device_name, create_params)) +/// Obtains a Chip with given chip_id +pub fn get(chip_id: ChipIdentifier) -> Result<Chip, String> { + get_with_singleton(chip_id, CHIPS.clone()) +} + +/// Testable function for get() +fn get_with_singleton(chip_id: ChipIdentifier, shared_chips: SharedChips) -> Result<Chip, String> { + Ok(shared_chips + .lock() + .get(&chip_id) + .ok_or(format!("CHIPS does not contains key {chip_id}"))? + .clone()) +} + +/// Allocates a new chip. +pub fn new( + device_id: DeviceIdentifier, + device_name: &str, + create_params: &CreateParams, +) -> Result<Chip, String> { + new_with_singleton(device_id, device_name, create_params, CHIPS.clone(), &IDS) +} + +/// Testable function for new() +fn new_with_singleton( + device_id: DeviceIdentifier, + device_name: &str, + create_params: &CreateParams, + shared_chips: SharedChips, + id_factory: &RwLock<IdFactory<ChipIdentifier>>, +) -> Result<Chip, String> { + let id = id_factory.write().unwrap().next_id(); + let chip = Chip::new(id, device_id, device_name, create_params); + shared_chips.lock().insert(id, chip.clone()); + Ok(chip) +} + +#[cfg(test)] +mod tests { + use netsim_proto::stats::netsim_radio_stats; + + use crate::echip::mocked; + + use super::*; + + const DEVICE_ID: u32 = 0; + const DEVICE_NAME: &str = "device"; + const CHIP_KIND: ProtoChipKind = ProtoChipKind::UNSPECIFIED; + const ADDRESS: &str = "address"; + const MANUFACTURER: &str = "manufacturer"; + const PRODUCT_NAME: &str = "product_name"; + + fn new_test_chip( + emulated_chip: Option<SharedEmulatedChip>, + shared_chips: SharedChips, + id_factory: &RwLock<IdFactory<ChipIdentifier>>, + ) -> Chip { + let create_params = CreateParams { + kind: CHIP_KIND, + address: ADDRESS.to_string(), + name: None, + manufacturer: MANUFACTURER.to_string(), + product_name: PRODUCT_NAME.to_string(), + bt_properties: None, + }; + match new_with_singleton( + DEVICE_ID, + DEVICE_NAME, + &create_params, + shared_chips.clone(), + id_factory, + ) { + Ok(mut chip) => { + chip.emulated_chip = emulated_chip; + chip + } + Err(err) => { + unreachable!("{err:?}"); + } + } + } + + #[test] + fn test_new_and_get_with_singleton() { + // Construct a new Chip by calling new_test_chip, which calls new_with_singleton + let shared_chips = SharedChips(Arc::new(Mutex::new(HashMap::new()))); + let id_factory = RwLock::new(IdFactory::new(INITIAL_CHIP_ID, 1)); + let chip = new_test_chip(None, shared_chips.clone(), &id_factory); + + // Check if the Chip has been successfully inserted in SharedChips + let chip_id = chip.id; + assert!(shared_chips.lock().contains_key(&chip_id)); + + // Check if the get_with_singleton can successfully fetch the chip + let chip_result = get_with_singleton(chip_id, shared_chips.clone()); + assert!(chip_result.is_ok()); + + // Check if the fields are correctly populated + let chip = chip_result.unwrap(); + assert_eq!(chip.device_id, DEVICE_ID); + assert_eq!(chip.device_name, DEVICE_NAME); + assert!(chip.emulated_chip.is_none()); + assert_eq!(chip.kind, CHIP_KIND); + assert_eq!(chip.address, ADDRESS); + assert_eq!(chip.name, format!("chip-{chip_id}")); + assert_eq!(chip.manufacturer, MANUFACTURER); + assert_eq!(chip.product_name, PRODUCT_NAME); + } + + #[test] + fn test_chip_get_stats() { + // When emulated_chip is constructed + let mocked_echip = + mocked::new(&mocked::CreateParams { chip_kind: ProtoChipKind::UNSPECIFIED }, 0); + let shared_chips = SharedChips(Arc::new(Mutex::new(HashMap::new()))); + let id_factory = RwLock::new(IdFactory::new(INITIAL_CHIP_ID, 1)); + let chip = new_test_chip(Some(mocked_echip), shared_chips.clone(), &id_factory); + assert_eq!(netsim_radio_stats::Kind::UNSPECIFIED, chip.get_stats().first().unwrap().kind()); + + // When emulated_chip is not constructed + let chip = new_test_chip(None, shared_chips.clone(), &id_factory); + assert_eq!(Vec::<ProtoRadioStats>::new(), chip.get_stats()); + } + + #[test] + fn test_chip_get() { + let mocked_echip = + mocked::new(&mocked::CreateParams { chip_kind: ProtoChipKind::UNSPECIFIED }, 0); + let shared_chips = SharedChips(Arc::new(Mutex::new(HashMap::new()))); + let id_factory = RwLock::new(IdFactory::new(INITIAL_CHIP_ID, 1)); + let chip = new_test_chip(Some(mocked_echip.clone()), shared_chips.clone(), &id_factory); + + // Obtain actual chip.get() + let actual = chip.get().unwrap(); + + // Construct expected ProtoChip + let mut expected = mocked_echip.lock().get(); + expected.kind = EnumOrUnknown::new(chip.kind); + expected.id = chip.id; + expected.name = chip.name.clone(); + expected.manufacturer = chip.manufacturer.clone(); + expected.product_name = chip.product_name.clone(); + + // Compare + assert_eq!(expected, actual); + } + + #[test] + fn test_chip_patch() { + let mocked_echip = + mocked::new(&mocked::CreateParams { chip_kind: ProtoChipKind::UNSPECIFIED }, 0); + let shared_chips = SharedChips(Arc::new(Mutex::new(HashMap::new()))); + let id_factory = RwLock::new(IdFactory::new(INITIAL_CHIP_ID, 1)); + let mut chip = new_test_chip(Some(mocked_echip.clone()), shared_chips.clone(), &id_factory); + + // Construct the patch body for modifying manufacturer and product_name + let mut patch_body = ProtoChip::new(); + patch_body.manufacturer = "patched_manufacturer".to_string(); + patch_body.product_name = "patched_product_name".to_string(); + + // Perform Patch + assert!(chip.patch(&patch_body).is_ok()); + + // Check if fields of chip has been patched + assert_eq!(patch_body.manufacturer, chip.manufacturer); + assert_eq!(patch_body.product_name, chip.product_name) + } + + // TODO (b/309529194) + // Implement echip/mocked.rs to test emulated_chip level of patch and resets. } diff --git a/rust/daemon/src/devices/device.rs b/rust/daemon/src/devices/device.rs index 8048261..fc88983 100644 --- a/rust/daemon/src/devices/device.rs +++ b/rust/daemon/src/devices/device.rs @@ -20,7 +20,6 @@ use protobuf::Message; use crate::devices::chip; use crate::devices::chip::Chip; use crate::devices::chip::ChipIdentifier; -use crate::devices::chip::FacadeIdentifier; use netsim_proto::common::ChipKind as ProtoChipKind; use netsim_proto::model::Device as ProtoDevice; use netsim_proto::model::Orientation as ProtoOrientation; @@ -59,7 +58,6 @@ impl Device { pub struct AddChipResult { pub device_id: DeviceIdentifier, pub chip_id: ChipIdentifier, - pub facade_id: FacadeIdentifier, } impl Device { @@ -188,7 +186,7 @@ impl Device { } } - let chip = chip::chip_new(&self.name, chip_create_params)?; + let chip = chip::new(self.id, &self.name, chip_create_params)?; let chip_id = chip.id; self.chips.insert(chip_id, chip); diff --git a/rust/daemon/src/devices/devices_handler.rs b/rust/daemon/src/devices/devices_handler.rs index f75a7a1..dc96d5a 100644 --- a/rust/daemon/src/devices/devices_handler.rs +++ b/rust/daemon/src/devices/devices_handler.rs @@ -30,7 +30,9 @@ use crate::devices::device::AddChipResult; use crate::devices::device::Device; use crate::echip; use crate::events; -use crate::events::Event; +use crate::events::{ + ChipAdded, ChipRemoved, DeviceAdded, DevicePatched, DeviceRemoved, Event, Events, ShutDown, +}; use crate::ffi::ffi_response_writable::CxxServerResponseWriter; use crate::ffi::CxxServerResponseWriterWrapper; use crate::http_server::server_response::ResponseWritable; @@ -63,6 +65,7 @@ use std::collections::BTreeMap; use std::pin::Pin; use std::sync::mpsc::Receiver; use std::sync::Arc; +use std::sync::Mutex; use std::sync::RwLock; use std::sync::RwLockWriteGuard; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; @@ -141,14 +144,13 @@ pub fn add_chip( match result { // id_tuple = (DeviceIdentifier, ChipIdentifier) Ok((device_id, chip_id)) => { - let emulated_chip = echip::new(echip_create_params, device_id, chip_id); - let facade_id = emulated_chip.get_facade_id(); + let emulated_chip = echip::new(echip_create_params, chip_id); // Lock Device Resource { let devices_arc = get_devices(); let mut devices = devices_arc.write().unwrap(); - // Add the facade_id into the resources + // Add the emulated_chip into the resources devices .entries .get_mut(&device_id) @@ -163,14 +165,13 @@ pub fn add_chip( SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards"); } // Update Capture resource - events::publish(Event::ChipAdded { + events::publish(Event::ChipAdded(ChipAdded { chip_id, chip_kind, - facade_id, device_name: device_name.to_string(), builtin: chip_kind == ProtoChipKind::BLUETOOTH_BEACON, - }); - Ok(AddChipResult { device_id, chip_id, facade_id }) + })); + Ok(AddChipResult { device_id, chip_id }) } Err(err) => { warn!( @@ -185,7 +186,6 @@ pub fn add_chip( pub struct AddChipResultCxx { device_id: u32, chip_id: u32, - facade_id: u32, is_error: bool, } @@ -198,10 +198,6 @@ impl AddChipResultCxx { self.chip_id } - pub fn get_facade_id(&self) -> u32 { - self.facade_id - } - pub fn is_error(&self) -> bool { self.is_error } @@ -238,7 +234,6 @@ pub fn add_chip_cxx( return Box::new(AddChipResultCxx { device_id: u32::MAX, chip_id: u32::MAX, - facade_id: u32::MAX, is_error: true, }) } @@ -265,7 +260,6 @@ pub fn add_chip_cxx( return Box::new(AddChipResultCxx { device_id: u32::MAX, chip_id: u32::MAX, - facade_id: u32::MAX, is_error: true, }) } @@ -282,15 +276,11 @@ pub fn add_chip_cxx( Ok(result) => Box::new(AddChipResultCxx { device_id: result.device_id, chip_id: result.chip_id, - facade_id: result.facade_id, is_error: false, }), - Err(_) => Box::new(AddChipResultCxx { - device_id: u32::MAX, - chip_id: u32::MAX, - facade_id: u32::MAX, - is_error: true, - }), + Err(_) => { + Box::new(AddChipResultCxx { device_id: u32::MAX, chip_id: u32::MAX, is_error: true }) + } } } @@ -323,7 +313,7 @@ fn get_or_create_device( // Update last modified timestamp for devices devices.last_modified = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards"); - events::publish(Event::DeviceAdded { id, name: name.to_string(), builtin }); + events::publish(Event::DeviceAdded(DeviceAdded { id, name: name.to_string(), builtin })); (id, String::from(name)) } @@ -343,7 +333,7 @@ fn remove_device( guard.last_modified = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards"); // Publish DeviceRemoved Event - events::publish(Event::DeviceRemoved { id, name, builtin }); + events::publish(Event::DeviceRemoved(DeviceRemoved { id, name, builtin })); Ok(()) } @@ -382,12 +372,12 @@ pub fn remove_chip(device_id: DeviceIdentifier, chip_id: ChipIdentifier) -> Resu get_devices().write().unwrap().last_modified = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards"); } - events::publish(Event::ChipRemoved { + events::publish(Event::ChipRemoved(ChipRemoved { chip_id, device_id, remaining_nonbuiltin_devices, radio_stats, - }); + })); Ok(()) } Err(err) => { @@ -506,7 +496,7 @@ fn patch_device(id_option: Option<DeviceIdentifier>, patch_json: &str) -> Result .expect("Time went backwards"); // Publish Device Patched event - events::publish(Event::DevicePatched { id, name }); + events::publish(Event::DevicePatched(DevicePatched { id, name })); } result } @@ -528,7 +518,7 @@ fn patch_device(id_option: Option<DeviceIdentifier>, patch_json: &str) -> Result .expect("Time went backwards"); // Publish Device Patched event - events::publish(Event::DevicePatched { id, name }); + events::publish(Event::DevicePatched(DevicePatched { id, name })); } return result; } @@ -554,7 +544,7 @@ fn patch_device(id_option: Option<DeviceIdentifier>, patch_json: &str) -> Result .expect("Time went backwards"); // Publish Device Patched event - events::publish(Event::DevicePatched { id, name }); + events::publish(Event::DevicePatched(DevicePatched { id, name })); } result } @@ -572,17 +562,23 @@ fn distance(a: &ProtoPosition, b: &ProtoPosition) -> f32 { } #[allow(dead_code)] -fn get_distance(id: DeviceIdentifier, other_id: DeviceIdentifier) -> Result<f32, String> { +fn get_distance(id: ChipIdentifier, other_id: ChipIdentifier) -> Result<f32, String> { + let device_id = crate::devices::chip::get(id) + .or(Err(format!("No such device with chip_id {id}")))? + .device_id; + let other_device_id = crate::devices::chip::get(other_id) + .or(Err(format!("No such device with chip_id {other_id}")))? + .device_id; let devices_arc = get_devices(); let devices = devices_arc.read().unwrap(); let a = devices .entries - .get(&id) + .get(&device_id) .map(|device_ref| device_ref.position.clone()) .ok_or(format!("No such device with id {id}"))?; let b = devices .entries - .get(&other_id) + .get(&other_device_id) .map(|device_ref| device_ref.position.clone()) .ok_or(format!("No such device with id {other_id}"))?; Ok(distance(&a, &b)) @@ -715,11 +711,11 @@ fn handle_device_subscribe(writer: ResponseWritable, subscribe_json: &str) { let event_rx = events::subscribe(); // Timeout after 15 seconds with no event received match event_rx.recv_timeout(Duration::from_secs(15)) { - Ok(Event::DeviceAdded { .. }) - | Ok(Event::DeviceRemoved { .. }) - | Ok(Event::ChipAdded { .. }) - | Ok(Event::ChipRemoved { .. }) - | Ok(Event::DevicePatched { .. }) + Ok(Event::DeviceAdded(_)) + | Ok(Event::DeviceRemoved(_)) + | Ok(Event::ChipAdded(_)) + | Ok(Event::ChipRemoved(_)) + | Ok(Event::DevicePatched(_)) | Ok(Event::DeviceReset) => handle_device_list(writer), Err(err) => writer.put_error(404, format!("{err:?}").as_str()), _ => writer.put_error(404, "disconnecting due to unrelated event"), @@ -808,7 +804,7 @@ pub fn handle_device_cxx( ) } -/// return enum type for wait_devices +/// return enum type for check_device_event #[derive(Debug, PartialEq)] enum DeviceWaitStatus { LastDeviceRemoved, @@ -824,13 +820,13 @@ fn check_device_event( ) -> DeviceWaitStatus { let wait_time = timeout_time.map_or(Duration::from_secs(u64::MAX), |t| t - Instant::now()); match events_rx.recv_timeout(wait_time) { - Ok(Event::ChipRemoved { remaining_nonbuiltin_devices: 0, .. }) => { + Ok(Event::ChipRemoved(ChipRemoved { remaining_nonbuiltin_devices: 0, .. })) => { DeviceWaitStatus::LastDeviceRemoved } // DeviceAdded (event from CreateDevice) // ChipAdded (event from add_chip or add_chip_cxx) - Ok(Event::DeviceAdded { builtin: false, .. }) - | Ok(Event::ChipAdded { builtin: false, .. }) => DeviceWaitStatus::DeviceAdded, + Ok(Event::DeviceAdded(DeviceAdded { builtin: false, .. })) + | Ok(Event::ChipAdded(ChipAdded { builtin: false, .. })) => DeviceWaitStatus::DeviceAdded, Err(_) => DeviceWaitStatus::Timeout, _ => DeviceWaitStatus::IgnoreEvent, } @@ -840,29 +836,40 @@ fn check_device_event( /// the function will publish a ShutDown event when /// 1. Initial timeout before first device is added /// 2. Last Chip Removed from netsimd -pub fn wait_devices(events_rx: Receiver<Event>) { - // TODO (b/303281633): Add unit tests for wait_devices +/// this function should NOT be invoked if running in no-shutdown mode +pub fn spawn_shutdown_publisher(events_rx: Receiver<Event>) { + spawn_shutdown_publisher_with_timeout(events_rx, IDLE_SECS_FOR_SHUTDOWN, events::get_events()); +} + +// separate function for testability +fn spawn_shutdown_publisher_with_timeout( + events_rx: Receiver<Event>, + timeout_duration_s: u64, + events_tx: Arc<Mutex<Events>>, +) { let _ = std::thread::Builder::new().name("device_event_subscriber".to_string()).spawn(move || { - let mut timeout_time = - Some(Instant::now() + Duration::from_secs(IDLE_SECS_FOR_SHUTDOWN)); + let publish_event = + |e: Event| events_tx.lock().expect("Failed to acquire lock on events").publish(e); + + let mut timeout_time = Some(Instant::now() + Duration::from_secs(timeout_duration_s)); loop { match check_device_event(&events_rx, timeout_time) { DeviceWaitStatus::LastDeviceRemoved => { - events::publish(Event::ShutDown { + publish_event(Event::ShutDown(ShutDown { reason: "last device disconnected".to_string(), - }); + })); return; } DeviceWaitStatus::DeviceAdded => { timeout_time = None; } DeviceWaitStatus::Timeout => { - events::publish(Event::ShutDown { + publish_event(Event::ShutDown(ShutDown { reason: format!( "no devices connected within {IDLE_SECS_FOR_SHUTDOWN}s" ), - }); + })); return; } DeviceWaitStatus::IgnoreEvent => continue, @@ -1007,6 +1014,148 @@ mod tests { } } + fn spawn_shutdown_publisher_test_setup(timeout: u64) -> (Arc<Mutex<Events>>, Receiver<Event>) { + let mut events = events::test::new(); + let events_rx = events::test::subscribe(&mut events); + spawn_shutdown_publisher_with_timeout(events_rx, timeout, events.clone()); + + let events_rx2 = events::test::subscribe(&mut events); + + (events, events_rx2) + } + + #[test] + fn test_spawn_shutdown_publisher_last_chip_removed() { + let (mut events, events_rx) = spawn_shutdown_publisher_test_setup(IDLE_SECS_FOR_SHUTDOWN); + + events::test::publish( + &mut events, + Event::ChipRemoved(ChipRemoved { + remaining_nonbuiltin_devices: 0, + ..Default::default() + }), + ); + + // receive our own ChipRemoved + assert!(matches!(events_rx.recv(), Ok(Event::ChipRemoved(ChipRemoved { .. })))); + // receive the ShutDown emitted by the function under test + assert!(matches!(events_rx.recv(), Ok(Event::ShutDown(ShutDown { .. })))); + } + + #[test] + fn test_spawn_shutdown_publisher_chip_removed_which_is_not_last_chip() { + let (mut events, events_rx) = spawn_shutdown_publisher_test_setup(IDLE_SECS_FOR_SHUTDOWN); + events::test::publish( + &mut events, + Event::ChipRemoved(ChipRemoved { + chip_id: 1, + remaining_nonbuiltin_devices: 1, + ..Default::default() + }), + ); + + // give other thread time to generate a ShutDown if it was going to + std::thread::sleep(std::time::Duration::from_secs(1)); + + // only the 2nd ChipRemoved should generate a ShutDown as it is marked the last one + events::test::publish( + &mut events, + Event::ChipRemoved(ChipRemoved { + chip_id: 0, + remaining_nonbuiltin_devices: 0, + ..Default::default() + }), + ); + + // receive our own ChipRemoved + assert!(matches!(events_rx.recv(), Ok(Event::ChipRemoved(ChipRemoved { .. })))); + // receive our own ChipRemoved (with no shutdown) + assert!(matches!(events_rx.recv(), Ok(Event::ChipRemoved(ChipRemoved { .. })))); + // only then receive the ShutDown emitted by the function under test + assert!(matches!(events_rx.recv(), Ok(Event::ShutDown(ShutDown { .. })))); + } + + #[test] + fn test_spawn_shutdown_publisher_last_chip_removed_with_duplicate_event() { + let (mut events, events_rx) = spawn_shutdown_publisher_test_setup(IDLE_SECS_FOR_SHUTDOWN); + events::test::publish( + &mut events, + Event::ChipRemoved(ChipRemoved { + chip_id: 0, + remaining_nonbuiltin_devices: 0, + ..Default::default() + }), + ); + + // give other thread time to generate a ShutDown if it was going to + std::thread::sleep(std::time::Duration::from_secs(1)); + + // this is a duplicate event and we already sent that all chips were removed + // this is for strict comparison with test_spawn_shutdown_publisher_chip_removed_which_is_not_last_chip + // to validate that if the first event has remaining_nonbuiltin_devices 0 + // we would receive ChipRemoved, ShutDown, ChipRemoved + // but if first ChipRemoved has remaining_nonbuiltin_devices, + // we instead receive ChipRemoved, ChipRemoved, ShutDown + events::test::publish( + &mut events, + Event::ChipRemoved(ChipRemoved { + chip_id: 0, + remaining_nonbuiltin_devices: 0, + ..Default::default() + }), + ); + + // receive our own ChipRemoved + assert!(matches!(events_rx.recv(), Ok(Event::ChipRemoved(_)))); + // receive the ShutDown emitted by the function under test + assert!(matches!(events_rx.recv(), Ok(Event::ShutDown(_)))); + // receive our own erroneous ChipRemoved which occurs after we said all chips were removed + // this is just for strict comparison with test_spawn_shutdown_publisher_chip_removed_which_is_not_last_chip + assert!(matches!(events_rx.recv(), Ok(Event::ChipRemoved(_)))); + // should timeout now (no further events as we expect shutdown publisher thread to have stopped) + assert!(events_rx.recv_timeout(Duration::from_secs(2)).is_err()); + } + + #[test] + fn test_spawn_shutdown_publisher_timeout() { + let (_, events_rx) = spawn_shutdown_publisher_test_setup(1u64); + + // receive the ShutDown emitted by the function under test + assert!(matches!(events_rx.recv_timeout(Duration::from_secs(2)), Ok(Event::ShutDown(_)))); + } + + #[test] + fn test_spawn_shutdown_publisher_timeout_is_canceled_if_a_chip_is_added() { + let (mut events, events_rx) = spawn_shutdown_publisher_test_setup(1u64); + + events::test::publish( + &mut events, + Event::ChipAdded(ChipAdded { + chip_id: 0, + chip_kind: ProtoChipKind::BLUETOOTH, + ..Default::default() + }), + ); + assert!(matches!(events_rx.recv(), Ok(Event::ChipAdded(_)))); + + // should NO longer receive the ShutDown emitted by the function under test + // based on timeout removed when chip added + assert!(events_rx.recv_timeout(Duration::from_secs(2)).is_err()); + + events::test::publish( + &mut events, + Event::ChipRemoved(ChipRemoved { + chip_id: 0, + remaining_nonbuiltin_devices: 0, + ..Default::default() + }), + ); + // receive our own ChipRemoved + assert!(matches!(events_rx.recv(), Ok(Event::ChipRemoved(_)))); + // receive the ShutDown emitted by the function under test + assert!(matches!(events_rx.recv(), Ok(Event::ShutDown(_)))); + } + #[test] fn test_distance() { // Pythagorean quadruples @@ -1291,6 +1440,42 @@ mod tests { assert!(get_devices().read().unwrap().entries.get(&bt_chip_result.device_id).is_some()); } + #[test] + fn test_get_distance() { + // Initializing Logger + logger_setup(); + + // Add 2 chips of different devices + let bt_chip_params = test_chip_1_bt(); + let bt_chip_2_params = test_chip_2_bt(); + let bt_chip_result = bt_chip_params.add_chip().unwrap(); + let bt_chip_2_result = bt_chip_2_params.add_chip().unwrap(); + + // Patch the first chip + let mut patch_device_request = PatchDeviceRequest::new(); + let mut proto_device = ProtoDevice::new(); + let request_position = new_position(1.0, 1.0, 1.0); + proto_device.name = bt_chip_params.device_name; + proto_device.position = Some(request_position.clone()).into(); + patch_device_request.device = Some(proto_device.clone()).into(); + let patch_json = print_to_string(&patch_device_request).unwrap(); + patch_device(Some(bt_chip_result.device_id), patch_json.as_str()).unwrap(); + + // Patch the second chip + let mut patch_device_request = PatchDeviceRequest::new(); + let mut proto_device = ProtoDevice::new(); + let request_position = new_position(1.0, 4.0, 5.0); + proto_device.name = bt_chip_2_params.device_name; + proto_device.position = Some(request_position.clone()).into(); + patch_device_request.device = Some(proto_device.clone()).into(); + let patch_json = print_to_string(&patch_device_request).unwrap(); + patch_device(Some(bt_chip_2_result.device_id), patch_json.as_str()).unwrap(); + + // Verify the get_distance performs the correct computation of + // sqrt((1-1)**2 + (4-1)**2 + (5-1)**2) + assert_eq!(Ok(5.0), get_distance(bt_chip_result.chip_id, bt_chip_2_result.chip_id)) + } + #[allow(dead_code)] fn list_request() -> Request<Vec<u8>> { Request::builder() @@ -1542,7 +1727,7 @@ mod tests { } #[test] - fn test_wait_devices_initial_timeout() { + fn test_check_device_event_initial_timeout() { logger_setup(); let mut events = events::test::new(); @@ -1554,82 +1739,69 @@ mod tests { } #[test] - fn test_wait_devices_last_device_removed() { + fn test_check_device_event_last_device_removed() { logger_setup(); let mut events = events::test::new(); let events_rx = events::test::subscribe(&mut events); events::test::publish( &mut events, - Event::ChipRemoved { - chip_id: 0, - device_id: 0, + Event::ChipRemoved(ChipRemoved { remaining_nonbuiltin_devices: 0, - radio_stats: Vec::new(), - }, + ..Default::default() + }), ); assert_eq!(check_device_event(&events_rx, None), DeviceWaitStatus::LastDeviceRemoved); } #[test] - fn test_wait_devices_device_chip_added() { + fn test_check_device_event_device_chip_added() { logger_setup(); let mut events = events::test::new(); let events_rx = events::test::subscribe(&mut events); events::test::publish( &mut events, - Event::DeviceAdded { id: 0, name: "".to_string(), builtin: false }, + Event::DeviceAdded(DeviceAdded { id: 0, name: "".to_string(), builtin: false }), ); assert_eq!(check_device_event(&events_rx, None), DeviceWaitStatus::DeviceAdded); events::test::publish( &mut events, - Event::ChipAdded { - chip_id: 0, - chip_kind: ProtoChipKind::BLUETOOTH, - facade_id: 0, - device_name: "".to_string(), - builtin: false, - }, + Event::ChipAdded(ChipAdded { builtin: false, ..Default::default() }), ); assert_eq!(check_device_event(&events_rx, None), DeviceWaitStatus::DeviceAdded); } #[test] - fn test_wait_devices_ignore_event() { + fn test_check_device_event_ignore_event() { logger_setup(); let mut events = events::test::new(); let events_rx = events::test::subscribe(&mut events); - events::test::publish(&mut events, Event::DevicePatched { id: 0, name: "".to_string() }); + events::test::publish( + &mut events, + Event::DevicePatched(DevicePatched { id: 0, name: "".to_string() }), + ); assert_eq!(check_device_event(&events_rx, None), DeviceWaitStatus::IgnoreEvent); events::test::publish( &mut events, - Event::ChipRemoved { - chip_id: 0, - device_id: 0, + Event::ChipRemoved(ChipRemoved { remaining_nonbuiltin_devices: 1, - radio_stats: Vec::new(), - }, + ..Default::default() + }), ); assert_eq!(check_device_event(&events_rx, None), DeviceWaitStatus::IgnoreEvent); } #[test] - fn test_wait_devices_ignore_beacon() { + fn test_check_device_event_ignore_chip_added_for_builtin() { logger_setup(); let mut events = events::test::new(); let events_rx = events::test::subscribe(&mut events); events::test::publish( &mut events, - Event::ChipAdded { - chip_id: 0, - chip_kind: ProtoChipKind::BLUETOOTH_BEACON, - facade_id: 0, - device_name: "".to_string(), - builtin: true, - }, + Event::ChipAdded(ChipAdded { builtin: true, ..Default::default() }), ); assert_eq!(check_device_event(&events_rx, None), DeviceWaitStatus::IgnoreEvent); } diff --git a/rust/daemon/src/echip/ble_beacon.rs b/rust/daemon/src/echip/ble_beacon.rs index 52f4303..0b8dd9f 100644 --- a/rust/daemon/src/echip/ble_beacon.rs +++ b/rust/daemon/src/echip/ble_beacon.rs @@ -14,16 +14,15 @@ use crate::bluetooth::{ble_beacon_add, ble_beacon_get, ble_beacon_patch, ble_beacon_remove}; use crate::devices::chip::{ChipIdentifier, FacadeIdentifier}; -use crate::devices::device::DeviceIdentifier; use crate::echip::{EmulatedChip, SharedEmulatedChip}; -use log::error; +use log::{error, info}; use netsim_proto::common::ChipKind as ProtoChipKind; use netsim_proto::model::Chip as ProtoChip; use netsim_proto::model::ChipCreate as ChipCreateProto; use netsim_proto::stats::{netsim_radio_stats, NetsimRadioStats as ProtoRadioStats}; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; #[cfg(not(test))] use crate::ffi::ffi_bluetooth; @@ -48,7 +47,7 @@ impl EmulatedChip for BleBeacon { log::info!("BleBeacon::handle_request({packet:?})"); } - fn reset(&self) { + fn reset(&mut self) { #[cfg(not(test))] ffi_bluetooth::bluetooth_reset(self.facade_id); #[cfg(test)] @@ -64,13 +63,13 @@ impl EmulatedChip for BleBeacon { chip_proto } - fn patch(&self, chip: &ProtoChip) { + fn patch(&mut self, chip: &ProtoChip) { if let Err(err) = ble_beacon_patch(self.facade_id, self.chip_id, chip.ble_beacon()) { error!("{err:?}"); } } - fn remove(&self) { + fn remove(&mut self) { if let Err(err) = ble_beacon_remove(self.chip_id, self.facade_id) { error!("{err:?}"); } @@ -91,23 +90,21 @@ impl EmulatedChip for BleBeacon { fn get_kind(&self) -> ProtoChipKind { ProtoChipKind::BLUETOOTH_BEACON } - - fn get_facade_id(&self) -> FacadeIdentifier { - self.facade_id - } } /// Create a new Emulated BleBeacon Chip -pub fn new( - params: &CreateParams, - device_id: DeviceIdentifier, - chip_id: ChipIdentifier, -) -> SharedEmulatedChip { - match ble_beacon_add(device_id, params.device_name.clone(), chip_id, ¶ms.chip_proto) { - Ok(facade_id) => Arc::new(Box::new(BleBeacon { facade_id, chip_id })), +pub fn new(params: &CreateParams, chip_id: ChipIdentifier) -> SharedEmulatedChip { + match ble_beacon_add(params.device_name.clone(), chip_id, ¶ms.chip_proto) { + Ok(facade_id) => { + info!("BleBeacon EmulatedChip created with facade_id: {facade_id} chip_id: {chip_id}"); + SharedEmulatedChip(Arc::new(Mutex::new(Box::new(BleBeacon { facade_id, chip_id })))) + } Err(err) => { error!("{err:?}"); - Arc::new(Box::new(BleBeacon { facade_id: u32::MAX, chip_id: u32::MAX })) + SharedEmulatedChip(Arc::new(Mutex::new(Box::new(BleBeacon { + facade_id: u32::MAX, + chip_id: u32::MAX, + })))) } } } diff --git a/rust/daemon/src/echip/bluetooth.rs b/rust/daemon/src/echip/bluetooth.rs index bc5d605..96b130c 100644 --- a/rust/daemon/src/echip/bluetooth.rs +++ b/rust/daemon/src/echip/bluetooth.rs @@ -13,13 +13,11 @@ // limitations under the License. use crate::devices::chip::ChipIdentifier; +use crate::echip::{EmulatedChip, SharedEmulatedChip}; use crate::ffi::ffi_bluetooth; -use crate::{ - devices::device::DeviceIdentifier, - echip::{EmulatedChip, SharedEmulatedChip}, -}; use cxx::let_cxx_string; +use log::info; use netsim_proto::common::ChipKind as ProtoChipKind; use netsim_proto::config::Bluetooth as BluetoothConfig; use netsim_proto::configuration::Controller as RootcanalController; @@ -52,7 +50,7 @@ impl EmulatedChip for Bluetooth { ffi_bluetooth::handle_bt_request(self.rootcanal_id, packet[0], &packet[1..].to_vec()) } - fn reset(&self) { + fn reset(&mut self) { ffi_bluetooth::bluetooth_reset(self.rootcanal_id); } @@ -64,12 +62,12 @@ impl EmulatedChip for Bluetooth { chip_proto } - fn patch(&self, chip: &ProtoChip) { + fn patch(&mut self, chip: &ProtoChip) { let bluetooth_bytes = chip.bt().write_to_bytes().unwrap(); ffi_bluetooth::bluetooth_patch_cxx(self.rootcanal_id, &bluetooth_bytes); } - fn remove(&self) { + fn remove(&mut self) { // Lock to protect id_to_chip_info_ table in C++ let _unused = ECHIP_BT_MUTEX.lock().expect("Failed to acquire lock on ECHIP_BT_MUTEX"); ffi_bluetooth::bluetooth_remove(self.rootcanal_id); @@ -99,18 +97,10 @@ impl EmulatedChip for Bluetooth { fn get_kind(&self) -> ProtoChipKind { ProtoChipKind::BLUETOOTH } - - fn get_facade_id(&self) -> RootcanalIdentifier { - self.rootcanal_id - } } /// Create a new Emulated Bluetooth Chip -pub fn new( - create_params: &CreateParams, - device_id: DeviceIdentifier, - chip_id: ChipIdentifier, -) -> SharedEmulatedChip { +pub fn new(create_params: &CreateParams, chip_id: ChipIdentifier) -> SharedEmulatedChip { // Lock to protect id_to_chip_info_ table in C++ let _unused = ECHIP_BT_MUTEX.lock().expect("Failed to acquire lock on ECHIP_BT_MUTEX"); let_cxx_string!(cxx_address = create_params.address.clone()); @@ -118,19 +108,16 @@ pub fn new( Some(properties) => properties.write_to_bytes().unwrap(), None => Vec::new(), }; - let rootcanal_id = ffi_bluetooth::bluetooth_add(device_id, chip_id, &cxx_address, &proto_bytes); + let rootcanal_id = ffi_bluetooth::bluetooth_add(chip_id, &cxx_address, &proto_bytes); + info!("Bluetooth EmulatedChip created with rootcanal_id: {rootcanal_id} chip_id: {chip_id}"); let echip = Bluetooth { rootcanal_id }; - Arc::new(Box::new(echip)) + SharedEmulatedChip(Arc::new(Mutex::new(Box::new(echip)))) } /// Starts the Bluetooth service. -pub fn bluetooth_start( - config: &MessageField<BluetoothConfig>, - instance_num: u16, - disable_address_reuse: bool, -) { +pub fn bluetooth_start(config: &MessageField<BluetoothConfig>, instance_num: u16) { let proto_bytes = config.as_ref().unwrap_or_default().write_to_bytes().unwrap(); - ffi_bluetooth::bluetooth_start(&proto_bytes, instance_num, disable_address_reuse); + ffi_bluetooth::bluetooth_start(&proto_bytes, instance_num); } /// Stops the Bluetooth service. diff --git a/rust/daemon/src/echip/emulated_chip.rs b/rust/daemon/src/echip/emulated_chip.rs index a2cd532..27970a2 100644 --- a/rust/daemon/src/echip/emulated_chip.rs +++ b/rust/daemon/src/echip/emulated_chip.rs @@ -14,7 +14,7 @@ use std::{ collections::BTreeMap, - sync::{Arc, Mutex}, + sync::{Arc, Mutex, MutexGuard}, }; use lazy_static::lazy_static; @@ -24,13 +24,13 @@ use netsim_proto::model::Chip as ProtoChip; use netsim_proto::stats::NetsimRadioStats as ProtoRadioStats; use crate::{ - devices::{ - chip::{ChipIdentifier, FacadeIdentifier}, - device::DeviceIdentifier, - }, - echip::{ble_beacon, mocked, SharedEmulatedChip}, + devices::chip::ChipIdentifier, + echip::{ble_beacon, mocked}, }; +#[derive(Clone)] +pub struct SharedEmulatedChip(pub Arc<Mutex<Box<dyn EmulatedChip + Send + Sync>>>); + #[cfg(not(test))] use crate::echip::{bluetooth, wifi}; @@ -41,6 +41,12 @@ lazy_static! { Arc::new(Mutex::new(BTreeMap::new())); } +impl SharedEmulatedChip { + pub fn lock(&self) -> MutexGuard<Box<dyn EmulatedChip + Send + Sync>> { + self.0.lock().expect("Poisoned Shared Emulated lock") + } +} + /// Parameter for each constructor of Emulated Chips #[allow(clippy::large_enum_variant)] pub enum CreateParam { @@ -70,7 +76,7 @@ pub trait EmulatedChip { /// Reset the internal state of the emulated chip for the virtual device. /// The transmitted and received packet count will be set to 0 and the chip /// shall be in the enabled state following a call to this function. - fn reset(&self); + fn reset(&mut self); /// Return the Chip model protobuf from the emulated chip. This is part of /// the Frontend API. @@ -79,12 +85,12 @@ pub trait EmulatedChip { /// Patch the state of the emulated chip. For example enable/disable the /// chip's host-to-controller packet processing. This is part of the /// Frontend API - fn patch(&self, chip: &ProtoChip); + fn patch(&mut self, chip: &ProtoChip); /// Remove the emulated chip from the emulated chip library. No further calls will /// be made on this emulated chip. This is called when the packet stream from /// the virtual device closes. - fn remove(&self); + fn remove(&mut self); /// Return the NetsimRadioStats protobuf from the emulated chip. This is /// part of NetsimStats protobuf. @@ -92,10 +98,6 @@ pub trait EmulatedChip { /// Returns the kind of the emulated chip. fn get_kind(&self) -> ProtoChipKind; - - // TODO(b/311480905): Remove this method and get rid of facade_id in devices crate. - /// Returns Facade Identifier. - fn get_facade_id(&self) -> FacadeIdentifier; } /// Lookup for SharedEmulatedChip with chip_id @@ -108,29 +110,23 @@ pub fn get(chip_id: ChipIdentifier) -> Option<SharedEmulatedChip> { /// Returns None if chip_id is non-existent key. pub fn remove(chip_id: ChipIdentifier) -> Option<SharedEmulatedChip> { let echip = ECHIPS.lock().expect("Failed to acquire lock on ECHIPS").remove(&chip_id); - if echip.is_some() { - echip.clone().unwrap().remove(); - } + echip.clone()?.lock().remove(); echip } /// This is called when the transport module receives a new packet stream /// connection from a virtual device. -pub fn new( - create_param: &CreateParam, - device_id: DeviceIdentifier, - chip_id: ChipIdentifier, -) -> SharedEmulatedChip { +pub fn new(create_param: &CreateParam, chip_id: ChipIdentifier) -> SharedEmulatedChip { // Based on create_param, construct SharedEmulatedChip. let shared_echip = match create_param { - CreateParam::BleBeacon(params) => ble_beacon::new(params, device_id, chip_id), + CreateParam::BleBeacon(params) => ble_beacon::new(params, chip_id), #[cfg(not(test))] - CreateParam::Bluetooth(params) => bluetooth::new(params, device_id, chip_id), + CreateParam::Bluetooth(params) => bluetooth::new(params, chip_id), #[cfg(not(test))] - CreateParam::Wifi(params) => wifi::new(params, device_id, chip_id), + CreateParam::Wifi(params) => wifi::new(params, chip_id), #[cfg(not(test))] CreateParam::Uwb => todo!(), - CreateParam::Mock(params) => mocked::new(params, device_id), + CreateParam::Mock(params) => mocked::new(params, chip_id), }; // Insert into ECHIPS Map @@ -150,10 +146,9 @@ mod tests { fn test_echip_new() { let mock_param = CreateParam::Mock(mocked::CreateParams { chip_kind: ProtoChipKind::UNSPECIFIED }); - let mock_device_id = 0; let mock_chip_id = 0; - let echip = new(&mock_param, mock_device_id, mock_chip_id); - assert_eq!(echip.get_kind(), ProtoChipKind::UNSPECIFIED); - assert_eq!(echip.get(), ProtoChip::new()); + let echip = new(&mock_param, mock_chip_id); + assert_eq!(echip.lock().get_kind(), ProtoChipKind::UNSPECIFIED); + assert_eq!(echip.lock().get(), ProtoChip::new()); } } diff --git a/rust/daemon/src/echip/mocked.rs b/rust/daemon/src/echip/mocked.rs index 32406ad..00e4915 100644 --- a/rust/daemon/src/echip/mocked.rs +++ b/rust/daemon/src/echip/mocked.rs @@ -12,15 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::devices::chip::FacadeIdentifier; -use crate::devices::device::DeviceIdentifier; +use crate::devices::chip::ChipIdentifier; use crate::echip::{EmulatedChip, SharedEmulatedChip}; use netsim_proto::common::ChipKind as ProtoChipKind; use netsim_proto::model::Chip as ProtoChip; -use netsim_proto::stats::NetsimRadioStats as ProtoRadioStats; +use netsim_proto::stats::{netsim_radio_stats, NetsimRadioStats as ProtoRadioStats}; +use protobuf::EnumOrUnknown; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; /// Parameters for creating Mocked chips pub struct CreateParams { @@ -35,30 +35,36 @@ pub struct Mock { impl EmulatedChip for Mock { fn handle_request(&self, packet: &[u8]) {} - fn reset(&self) {} + fn reset(&mut self) {} fn get(&self) -> ProtoChip { - ProtoChip::new() + let mut proto_chip = ProtoChip::new(); + proto_chip.kind = EnumOrUnknown::new(self.chip_kind); + proto_chip } - fn patch(&self, chip: &ProtoChip) {} + fn patch(&mut self, chip: &ProtoChip) {} - fn remove(&self) {} + fn remove(&mut self) {} fn get_stats(&self, duration_secs: u64) -> Vec<ProtoRadioStats> { - vec![ProtoRadioStats::new()] + let mut stats = ProtoRadioStats::new(); + stats.kind = Some(EnumOrUnknown::new(match self.chip_kind { + ProtoChipKind::UNSPECIFIED => netsim_radio_stats::Kind::UNSPECIFIED, + ProtoChipKind::BLUETOOTH => netsim_radio_stats::Kind::BLUETOOTH_LOW_ENERGY, + ProtoChipKind::WIFI => netsim_radio_stats::Kind::WIFI, + ProtoChipKind::UWB => netsim_radio_stats::Kind::UWB, + ProtoChipKind::BLUETOOTH_BEACON => netsim_radio_stats::Kind::BLE_BEACON, + })); + vec![stats] } fn get_kind(&self) -> ProtoChipKind { self.chip_kind } - - fn get_facade_id(&self) -> FacadeIdentifier { - FacadeIdentifier::MIN - } } /// Create a new MockedChip -pub fn new(create_params: &CreateParams, device_id: DeviceIdentifier) -> SharedEmulatedChip { - Arc::new(Box::new(Mock { chip_kind: create_params.chip_kind })) +pub fn new(create_params: &CreateParams, _chip_id: ChipIdentifier) -> SharedEmulatedChip { + SharedEmulatedChip(Arc::new(Mutex::new(Box::new(Mock { chip_kind: create_params.chip_kind })))) } diff --git a/rust/daemon/src/echip/mod.rs b/rust/daemon/src/echip/mod.rs index 0b5fdb0..010c9e4 100644 --- a/rust/daemon/src/echip/mod.rs +++ b/rust/daemon/src/echip/mod.rs @@ -21,8 +21,6 @@ pub mod wifi; 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}; -use std::sync::Arc; - -pub type SharedEmulatedChip = Arc<Box<dyn EmulatedChip + Send + Sync>>; diff --git a/rust/daemon/src/echip/packet.rs b/rust/daemon/src/echip/packet.rs index 6a45a76..8140594 100644 --- a/rust/daemon/src/echip/packet.rs +++ b/rust/daemon/src/echip/packet.rs @@ -15,7 +15,7 @@ use std::collections::HashMap; use std::sync::{ mpsc::{channel, Sender}, - Arc, Mutex, + Arc, Mutex, MutexGuard, }; use std::thread; @@ -50,21 +50,27 @@ struct ResponsePacket { } // SENDERS is a singleton that contains a hash map from -// (kind,facade_id) to responder queue. +// chip_id to responder queue. + +type SenderMap = HashMap<ChipIdentifier, Sender<ResponsePacket>>; +struct SharedSenders(Arc<Mutex<SenderMap>>); + +impl SharedSenders { + fn lock(&self) -> MutexGuard<SenderMap> { + self.0.lock().expect("Poisoned Shared Senders lock") + } +} lazy_static! { - static ref SENDERS: Arc<Mutex<HashMap<ChipIdentifier, Sender<ResponsePacket>>>> = - Arc::new(Mutex::new(HashMap::new())); + static ref SENDERS: SharedSenders = SharedSenders(Arc::new(Mutex::new(HashMap::new()))); } /// Register a chip controller instance to a transport manager. pub fn register_transport(chip_id: ChipIdentifier, mut responder: Box<dyn Response + Send>) { let (tx, rx) = channel::<ResponsePacket>(); - let mut map = SENDERS.lock().expect("register_transport: poisoned lock"); - if map.contains_key(&chip_id) { + if SENDERS.lock().insert(chip_id, tx).is_some() { error!("register_transport: key already present for chip_id: {chip_id}"); } - map.insert(chip_id, tx); let _ = thread::Builder::new().name(format!("transport_writer_{chip_id}")).spawn(move || { info!("register_transport: started thread chip_id: {chip_id}"); loop { @@ -84,7 +90,7 @@ pub fn register_transport(chip_id: ChipIdentifier, mut responder: Box<dyn Respon /// Unregister a chip controller instance. pub fn unregister_transport(chip_id: ChipIdentifier) { // Shuts down the responder thread, because sender is dropped. - SENDERS.lock().expect("unregister_transport: poisoned lock").remove(&chip_id); + SENDERS.lock().remove(&chip_id); } // Handle response from facades. @@ -99,7 +105,7 @@ pub fn handle_response(chip_id: ChipIdentifier, packet: &cxx::CxxVector<u8>, pac let packet_vec = packet.as_slice().to_vec(); captures_handler::handle_packet_response(chip_id, &packet_vec, packet_type.into()); - let mut binding = SENDERS.lock().expect("Failed to acquire lock on SENDERS"); + let mut binding = SENDERS.lock(); if let Some(responder) = binding.get(&chip_id) { if responder.send(ResponsePacket { packet: packet_vec, packet_type }).is_err() { warn!("handle_response: send failed for chip_id: {chip_id}"); @@ -123,7 +129,7 @@ pub fn handle_request(chip_id: ChipIdentifier, packet: &mut Vec<u8>, packet_type // Perform handle_request match get(chip_id) { - Some(emulated_chip) => emulated_chip.handle_request(packet), + Some(emulated_chip) => emulated_chip.lock().handle_request(packet), None => warn!("SharedEmulatedChip doesn't exist for {chip_id}"), }; } @@ -148,17 +154,17 @@ mod tests { let val: Box<dyn Response + Send> = Box::new(TestTransport {}); register_transport(0, val); { - let binding = SENDERS.lock().unwrap(); + let binding = SENDERS.lock(); assert!(binding.contains_key(&0)); } - SENDERS.lock().unwrap().remove(&0); + SENDERS.lock().remove(&0); } #[test] fn test_unregister_transport() { register_transport(1, Box::new(TestTransport {})); unregister_transport(1); - assert!(SENDERS.lock().unwrap().get(&1).is_none()); + assert!(SENDERS.lock().get(&1).is_none()); } } diff --git a/rust/daemon/src/echip/wifi.rs b/rust/daemon/src/echip/wifi.rs index a73c76a..2dba81a 100644 --- a/rust/daemon/src/echip/wifi.rs +++ b/rust/daemon/src/echip/wifi.rs @@ -12,13 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::devices::chip::{ChipIdentifier, FacadeIdentifier}; +use crate::devices::chip::ChipIdentifier; +use crate::echip::{EmulatedChip, SharedEmulatedChip}; use crate::ffi::ffi_wifi; use crate::wifi::medium; -use crate::{ - devices::device::DeviceIdentifier, - echip::{EmulatedChip, SharedEmulatedChip}, -}; +use log::info; use netsim_proto::common::ChipKind as ProtoChipKind; use netsim_proto::config::WiFi as WiFiConfig; use netsim_proto::model::chip::Radio; @@ -26,12 +24,12 @@ use netsim_proto::model::Chip as ProtoChip; use netsim_proto::stats::{netsim_radio_stats, NetsimRadioStats as ProtoRadioStats}; use protobuf::{Message, MessageField}; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; /// Parameters for creating Wifi chips pub struct CreateParams {} -/// Wifi struct will keep track of facade_id +/// Wifi struct will keep track of chip_id pub struct Wifi { chip_id: ChipIdentifier, } @@ -44,7 +42,7 @@ impl EmulatedChip for Wifi { ffi_wifi::handle_wifi_request(self.chip_id, &packet.to_vec()); } - fn reset(&self) { + fn reset(&mut self) { ffi_wifi::wifi_reset(self.chip_id); } @@ -56,12 +54,12 @@ impl EmulatedChip for Wifi { chip_proto } - fn patch(&self, chip: &ProtoChip) { + fn patch(&mut self, chip: &ProtoChip) { let radio_bytes = chip.wifi().write_to_bytes().unwrap(); ffi_wifi::wifi_patch_cxx(self.chip_id, &radio_bytes); } - fn remove(&self) { + fn remove(&mut self) { ffi_wifi::wifi_remove(self.chip_id); } @@ -80,21 +78,14 @@ impl EmulatedChip for Wifi { fn get_kind(&self) -> ProtoChipKind { ProtoChipKind::WIFI } - - fn get_facade_id(&self) -> FacadeIdentifier { - self.chip_id - } } /// Create a new Emulated Wifi Chip -pub fn new( - _params: &CreateParams, - _device_id: DeviceIdentifier, - chip_id: ChipIdentifier, -) -> SharedEmulatedChip { +pub fn new(_params: &CreateParams, chip_id: ChipIdentifier) -> SharedEmulatedChip { ffi_wifi::wifi_add(chip_id); + info!("WiFi EmulatedChip created chip_id: {chip_id}"); let echip = Wifi { chip_id }; - Arc::new(Box::new(echip)) + SharedEmulatedChip(Arc::new(Mutex::new(Box::new(echip)))) } /// Starts the WiFi service. diff --git a/rust/daemon/src/events.rs b/rust/daemon/src/events.rs index a670ceb..1d13af2 100644 --- a/rust/daemon/src/events.rs +++ b/rust/daemon/src/events.rs @@ -18,7 +18,6 @@ use netsim_proto::common::ChipKind; use std::sync::mpsc::{channel, Receiver, Sender}; use crate::devices::chip::ChipIdentifier; -use crate::devices::chip::FacadeIdentifier; use crate::devices::device::DeviceIdentifier; use netsim_proto::stats::NetsimRadioStats as ProtoRadioStats; @@ -35,48 +34,65 @@ pub fn subscribe() -> Receiver<Event> { get_events().lock().expect("Failed to acquire locks on events").subscribe() } +#[derive(Clone, Debug, Default)] +pub struct DeviceAdded { + pub id: DeviceIdentifier, + pub name: String, + pub builtin: bool, +} + +#[derive(Clone, Debug, Default)] +pub struct DeviceRemoved { + pub id: DeviceIdentifier, + pub name: String, + pub builtin: bool, +} + +#[derive(Clone, Debug, Default)] +pub struct DevicePatched { + pub id: DeviceIdentifier, + pub name: String, +} + +#[derive(Clone, Debug, Default)] +pub struct ChipAdded { + pub chip_id: ChipIdentifier, + pub chip_kind: ChipKind, + pub device_name: String, + pub builtin: bool, +} + +#[derive(Clone, Debug, Default)] +pub struct ChipRemoved { + pub chip_id: ChipIdentifier, + pub device_id: DeviceIdentifier, + pub remaining_nonbuiltin_devices: usize, + pub radio_stats: Vec<ProtoRadioStats>, +} + +#[derive(Clone, Debug, Default)] +pub struct ShutDown { + pub reason: String, +} + /// Event messages shared across various components in a loosely /// coupled manner. #[derive(Clone, Debug)] pub enum Event { - DeviceAdded { - id: DeviceIdentifier, - name: String, - builtin: bool, - }, - DeviceRemoved { - id: DeviceIdentifier, - name: String, - builtin: bool, - }, - DevicePatched { - id: DeviceIdentifier, - name: String, - }, + DeviceAdded(DeviceAdded), + DeviceRemoved(DeviceRemoved), + DevicePatched(DevicePatched), DeviceReset, - ChipAdded { - chip_id: ChipIdentifier, - chip_kind: ChipKind, - facade_id: FacadeIdentifier, - device_name: String, - builtin: bool, - }, - ChipRemoved { - chip_id: ChipIdentifier, - device_id: DeviceIdentifier, - remaining_nonbuiltin_devices: usize, - radio_stats: Vec<ProtoRadioStats>, - }, - ShutDown { - reason: String, - }, + ChipAdded(ChipAdded), + ChipRemoved(ChipRemoved), + ShutDown(ShutDown), } lazy_static! { static ref EVENTS: Arc<Mutex<Events>> = Events::new(); } -fn get_events() -> Arc<Mutex<Events>> { +pub fn get_events() -> Arc<Mutex<Events>> { Arc::clone(&EVENTS) } @@ -111,7 +127,7 @@ impl Events { } // Attempts to send an Event on the events channel. - fn publish(&mut self, msg: Event) { + pub fn publish(&mut self, msg: Event) { if self.subscribers.is_empty() { log::warn!("No Subscribers to the event: {msg:?}"); } else { @@ -155,18 +171,18 @@ mod tests { let events_clone = Arc::clone(&events); let rx = events_clone.lock().unwrap().subscribe(); let handle = thread::spawn(move || match rx.recv() { - Ok(Event::DeviceAdded { id, name, builtin: false }) => { + Ok(Event::DeviceAdded(DeviceAdded { id, name, builtin: false })) => { assert_eq!(id, 123); assert_eq!(name, "Device1"); } _ => panic!("Unexpected event"), }); - events.lock().unwrap().publish(Event::DeviceAdded { + events.lock().unwrap().publish(Event::DeviceAdded(DeviceAdded { id: 123, name: "Device1".into(), builtin: false, - }); + })); // Wait for the other thread to process the message. handle.join().unwrap(); @@ -182,7 +198,7 @@ mod tests { let events_clone = Arc::clone(&events); let rx = events_clone.lock().unwrap().subscribe(); let handle = thread::spawn(move || match rx.recv() { - Ok(Event::DeviceAdded { id, name, builtin: false }) => { + Ok(Event::DeviceAdded(DeviceAdded { id, name, builtin: false })) => { assert_eq!(id, 123); assert_eq!(name, "Device1"); } @@ -191,11 +207,11 @@ mod tests { handles.push(handle); } - events.lock().unwrap().publish(Event::DeviceAdded { + events.lock().unwrap().publish(Event::DeviceAdded(DeviceAdded { id: 123, name: "Device1".into(), builtin: false, - }); + })); // Wait for the other threads to process the message. for handle in handles { @@ -212,11 +228,11 @@ mod tests { let rx = events.lock().unwrap().subscribe(); assert_eq!(events.lock().unwrap().subscribers.len(), 1); std::mem::drop(rx); - events.lock().unwrap().publish(Event::DeviceAdded { + events.lock().unwrap().publish(Event::DeviceAdded(DeviceAdded { id: 123, name: "Device1".into(), builtin: false, - }); + })); assert_eq!(events.lock().unwrap().subscribers.len(), 0); } } diff --git a/rust/daemon/src/ffi.rs b/rust/daemon/src/ffi.rs index b33c145..5a06c13 100644 --- a/rust/daemon/src/ffi.rs +++ b/rust/daemon/src/ffi.rs @@ -185,12 +185,7 @@ pub mod ffi_bluetooth { #[rust_name = bluetooth_add] #[namespace = "netsim::hci::facade"] - pub fn Add( - device_id: u32, - chip_id: u32, - address: &CxxString, - controller_proto_bytes: &[u8], - ) -> u32; + pub fn Add(chip_id: u32, address: &CxxString, controller_proto_bytes: &[u8]) -> u32; /* From https://cxx.rs/binding/box.html#restrictions, @@ -206,7 +201,7 @@ pub mod ffi_bluetooth { #[rust_name = bluetooth_add_rust_device] #[namespace = "netsim::hci::facade"] pub fn AddRustDevice( - device_id: u32, + chip_id: u32, callbacks: Box<DynRustBluetoothChipCallbacks>, string_type: &CxxString, address: &CxxString, @@ -223,7 +218,7 @@ pub mod ffi_bluetooth { #[rust_name = bluetooth_start] #[namespace = "netsim::hci::facade"] - pub fn Start(proto_bytes: &[u8], instance_num: u16, disable_address_reuse: bool); + pub fn Start(proto_bytes: &[u8], instance_num: u16); #[rust_name = bluetooth_stop] #[namespace = "netsim::hci::facade"] @@ -279,8 +274,6 @@ pub mod ffi_devices { fn get_device_id(self: &AddChipResultCxx) -> u32; #[cxx_name = "GetChipId"] fn get_chip_id(self: &AddChipResultCxx) -> u32; - #[cxx_name = "GetFacadeId"] - fn get_facade_id(self: &AddChipResultCxx) -> u32; #[cxx_name = "IsError"] fn is_error(self: &AddChipResultCxx) -> bool; diff --git a/rust/daemon/src/rust_main.rs b/rust/daemon/src/rust_main.rs index 8833700..a0a8aa1 100644 --- a/rust/daemon/src/rust_main.rs +++ b/rust/daemon/src/rust_main.rs @@ -21,10 +21,10 @@ use netsim_common::util::zip_artifact::zip_artifacts; use crate::captures::capture::spawn_capture_event_subscriber; use crate::config_file; -use crate::devices::devices_handler::wait_devices; +use crate::devices::devices_handler::spawn_shutdown_publisher; use crate::echip; use crate::events; -use crate::events::Event; +use crate::events::{Event, ShutDown}; use crate::session::Session; use crate::version::get_version; use netsim_common::util::netsim_logger; @@ -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::Config; +use netsim_proto::config::{Bluetooth as BluetoothConfig, Config}; use std::env; use std::ffi::{c_char, c_int}; use std::sync::mpsc::Receiver; @@ -144,15 +144,13 @@ fn run_netsimd_connector(args: NetsimdArgs, instance: u16) { } // loop until ShutDown event is received, then log and return. -fn main_loop(events_rx: Receiver<Event>, no_shutdown_flag: bool) { +fn main_loop(events_rx: Receiver<Event>) { loop { // events_rx.recv() will wait until the event is received. // TODO(b/305536480): Remove built-in devices during shutdown. - if let Ok(Event::ShutDown { reason }) = events_rx.recv() { + if let Ok(Event::ShutDown(ShutDown { reason })) = events_rx.recv() { info!("Netsim is shutdown: {reason}"); - if !no_shutdown_flag { - return; - } + return; } } } @@ -193,7 +191,7 @@ fn run_netsimd_primary(args: NetsimdArgs) { fd_startup_str, args.no_cli_ui, args.no_web_ui, - args.pcap, + config.capture.enabled == Some(true) || args.pcap, hci_port, instance_num, args.dev, @@ -217,20 +215,39 @@ fn run_netsimd_primary(args: NetsimdArgs) { // Pass all event receivers to each modules spawn_capture_event_subscriber(capture_events_rx); - wait_devices(device_events_rx); + + if !args.no_shutdown { + 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, args.disable_address_reuse); + 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 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"), - } { + 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"), + } + { new_test_beacon(1, 1000); new_test_beacon(2, 1000); } @@ -239,7 +256,7 @@ fn run_netsimd_primary(args: NetsimdArgs) { service.run(); // Runs a synchronous main loop - main_loop(main_events_rx, args.no_shutdown); + main_loop(main_events_rx); // Gracefully shutdown netsimd services service.shut_down(); diff --git a/rust/daemon/src/session.rs b/rust/daemon/src/session.rs index f3a9097..ac87adc 100644 --- a/rust/daemon/src/session.rs +++ b/rust/daemon/src/session.rs @@ -15,7 +15,7 @@ //! A module to collect and write session stats use crate::devices::devices_handler::get_radio_stats; -use crate::events::Event; +use crate::events::{ChipRemoved, Event, ShutDown}; use crate::version::get_version; use anyhow::Context; use log::error; @@ -83,17 +83,17 @@ impl Session { Duration::ZERO }; match events_rx.recv_timeout(timeout) { - Ok(Event::ShutDown { reason }) => { + Ok(Event::ShutDown(ShutDown { reason })) => { // Shutting down, save the session duration and exit update_session_duration(&mut lock); return reason; } - Ok(Event::DeviceRemoved { .. }) => { + Ok(Event::DeviceRemoved(_)) => { lock.current_device_count -= 1; } - Ok(Event::DeviceAdded { .. }) => { + Ok(Event::DeviceAdded(_)) => { // update the current_device_count and peak device usage lock.current_device_count += 1; let current_device_count = lock.current_device_count; @@ -108,7 +108,9 @@ impl Session { } } - Ok(Event::ChipRemoved { radio_stats, device_id, .. }) => { + Ok(Event::ChipRemoved(ChipRemoved { + radio_stats, device_id, .. + })) => { // Update the radio stats proto when a // chip is removed. In the case of // bluetooth there will be 2 radios, @@ -119,10 +121,13 @@ impl Session { } } + Ok(Event::ChipAdded(_)) => { + // No session stat update required when Chip is added but do proceed to write stats + } _ => { // other events are ignored, check to perform periodic write if next_instant > Instant::now() { - write_stats = false + write_stats = false; } } } diff --git a/rust/daemon/src/transport/fd.rs b/rust/daemon/src/transport/fd.rs index 9175e8e..2acb0dd 100644 --- a/rust/daemon/src/transport/fd.rs +++ b/rust/daemon/src/transport/fd.rs @@ -102,7 +102,6 @@ impl Response for FdTransport { unsafe fn fd_reader( fd_rx: i32, kind: ChipKindEnum, - facade_id: u32, device_id: u32, chip_id: u32, ) -> JoinHandle<()> { @@ -112,7 +111,7 @@ unsafe fn fd_reader( // SAFETY: The caller promises that `fd_rx` is valid and open. let mut rx = unsafe { File::from_raw_fd(fd_rx) }; - info!("Handling fd={} for kind: {:?} facade_id: {:?}", fd_rx, kind, facade_id); + info!("Handling fd={} for kind: {:?} chip_id: {:?}", fd_rx, kind, chip_id); loop { match kind { @@ -258,13 +257,7 @@ pub unsafe fn run_fd_transport(startup_json: &String) { // SAFETY: Our caller promises that the file descriptors in the JSON are valid // and open. handles.push(unsafe { - fd_reader( - chip.fd_out as i32, - chip.kind, - result.facade_id, - result.device_id, - result.chip_id, - ) + fd_reader(chip.fd_out as i32, chip.kind, result.device_id, result.chip_id) }); } } diff --git a/rust/daemon/src/version.rs b/rust/daemon/src/version.rs index bb9e584..2a0cbc9 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.2"; +pub const VERSION: &str = "0.2.3"; 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 7737ae5..4b8f462 100644 --- a/rust/daemon/src/wifi/frame.rs +++ b/rust/daemon/src/wifi/frame.rs @@ -12,10 +12,10 @@ // 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 crate::wifi::packets::ieee80211::Ieee80211; use anyhow::{anyhow, Context}; use log::{info, warn}; use std::mem; @@ -58,14 +58,14 @@ struct FrameBuilder { #[derive(Debug)] pub struct Frame { - transmitter: [u8; 6], + transmitter: Option<[u8; 6]>, receiver: Option<[u8; 6]>, pub data: Vec<u8>, pub ieee80211_hdr: Option<Ieee80211>, - pub flags: u32, + pub flags: Option<u32>, rx_rate_idx: Option<u32>, pub signal: Option<u32>, - cookie: u64, + cookie: Option<u64>, pub freq: Option<u32>, tx_rates: Option<Vec<TxRate>>, tx_rate_flags: Option<Vec<TxRateFlag>>, @@ -130,10 +130,10 @@ impl FrameBuilder { let data = self.data.ok_or(anymsg("frame"))?; let ieee80211_hdr = Ieee80211::parse(&data).ok(); Ok(Frame { - transmitter: self.transmitter.ok_or(anymsg("transmitter"))?, + transmitter: self.transmitter, receiver: self.receiver, - cookie: self.cookie.ok_or(anymsg("cookie"))?, - flags: self.flags.ok_or(anymsg("flags"))?, + cookie: self.cookie, + flags: self.flags, rx_rate_idx: self.rx_rate_idx, signal: self.signal, data, diff --git a/rust/daemon/src/wifi/ieee80211.rs b/rust/daemon/src/wifi/ieee80211.rs index d5a4f1e..7e501b8 100644 --- a/rust/daemon/src/wifi/ieee80211.rs +++ b/rust/daemon/src/wifi/ieee80211.rs @@ -12,12 +12,108 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// FrameInfo stores mac80211 hwsim attributes once parsed - -pub struct FrameInfo { - cookie: u64, - flags: u32, - channel: u32, - // tx_rates - transmitter: [u8; 6], +//! ieee80211 frames + +#![allow(clippy::all)] +#![allow(missing_docs)] +include!(concat!(env!("OUT_DIR"), "/ieee80211_packets.rs")); + +/// A Ieee80211 MAC address + +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], + ) + } +} + +impl From<&[u8; 6]> for MacAddress { + fn from(bytes: &[u8; 6]) -> Self { + Self(u64::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], 0, 0])) + } +} + +impl From<MacAddress> for [u8; 6] { + fn from(MacAddress(addr): MacAddress) -> Self { + let bytes = u64::to_le_bytes(addr); + bytes[0..6].try_into().unwrap() + } +} + +impl Ieee80211 { + // Frame has addr4 field + pub fn has_a4(&self) -> bool { + self.ieee80211.to_ds == 1 || self.ieee80211.from_ds == 1 + } + + // Frame type is management + pub fn is_mgmt(&self) -> bool { + self.ieee80211.ftype == FrameType::Mgmt + } + + // Frame type is data + pub fn is_data(&self) -> bool { + self.ieee80211.ftype == FrameType::Data + } + + // Frame is probe request + pub fn is_probe_req(&self) -> bool { + self.ieee80211.ftype == FrameType::Ctl + && self.ieee80211.stype == (ManagementSubType::ProbeReq as u8) + } + + pub fn get_source(&self) -> MacAddress { + match self.specialize() { + Ieee80211Child::Ieee80211ToAp(hdr) => hdr.get_source(), + Ieee80211Child::Ieee80211FromAp(hdr) => hdr.get_source(), + Ieee80211Child::Ieee80211Ibss(hdr) => hdr.get_source(), + Ieee80211Child::Ieee80211Wds(hdr) => hdr.get_source(), + _ => panic!("unexpected specialized header"), + } + } +} + +fn parse_mac_address(s: &str) -> Option<MacAddress> { + let parts: Vec<&str> = s.split(':').collect(); + if parts.len() != 6 { + return None; + } + let mut bytes = [0u8; 6]; + for (i, part) in parts.iter().enumerate() { + match u8::from_str_radix(part, 16) { + Ok(n) => bytes[i] = n, + Err(e) => return None, + } + } + Some(MacAddress::from(&bytes)) +} + +#[cfg(test)] +mod tests { + use super::*; + + // These tests use the packets available here + // https://community.cisco.com/t5/wireless-mobility-knowledge-base/802-11-frames-a-starter-guide-to-learn-wireless-sniffer-traces/ta-p/3110019 + + #[test] + fn test_frame_qos() { + let frame: Vec<u8> = vec![ + 0x88, 0x02, 0x2c, 0x00, 0x00, 0x13, 0xe8, 0xeb, 0xd6, 0x03, 0x00, 0x0b, 0x85, 0x71, + 0x20, 0xce, 0x00, 0x0b, 0x85, 0x71, 0x20, 0xce, 0x00, 0x26, 0x00, 0x00, + ]; + let hdr = Ieee80211::parse(&frame).unwrap(); + assert!(hdr.is_data()); + assert_eq!(hdr.get_stype(), DataSubType::Qos as u8); + assert_eq!(hdr.get_from_ds(), 1); + assert_eq!(hdr.get_to_ds(), 0); + assert_eq!(hdr.get_duration_id(), 44); + // Source address: Cisco_71:20:ce (00:0b:85:71:20:ce) + let a = format!("{}", hdr.get_source()); + let b = format!("{}", parse_mac_address("00:0b:85:71:20:ce").unwrap()); + assert_eq!(a, b); + } } diff --git a/rust/daemon/src/wifi/medium.rs b/rust/daemon/src/wifi/medium.rs index 29a4588..11454df 100644 --- a/rust/daemon/src/wifi/medium.rs +++ b/rust/daemon/src/wifi/medium.rs @@ -61,7 +61,47 @@ pub fn test_parse_hwsim_cmd() { 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, ]; - parse_hwsim_cmd(&packet); + 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()); } #[cfg(test)] diff --git a/rust/daemon/src/wifi/mod.rs b/rust/daemon/src/wifi/mod.rs index 43c6260..8891cce 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 ieee80211; pub(crate) mod medium; pub(crate) mod packets; pub(crate) mod radiotap; diff --git a/rust/daemon/src/wifi/packets.rs b/rust/daemon/src/wifi/packets.rs index 934b707..a3f9987 100644 --- a/rust/daemon/src/wifi/packets.rs +++ b/rust/daemon/src/wifi/packets.rs @@ -27,11 +27,3 @@ pub mod mac80211_hwsim { include!(concat!(env!("OUT_DIR"), "/mac80211_hwsim_packets.rs")); } - -pub mod ieee80211 { - #![allow(clippy::all)] - #![allow(unused)] - #![allow(missing_docs)] - - include!(concat!(env!("OUT_DIR"), "/ieee80211_packets.rs")); -} diff --git a/rust/proto/src/config.rs b/rust/proto/src/config.rs index eefe931..8c37c32 100644 --- a/rust/proto/src/config.rs +++ b/rust/proto/src/config.rs @@ -723,8 +723,10 @@ pub struct Bluetooth { // message fields // @@protoc_insertion_point(field:netsim.config.Bluetooth.properties) pub properties: ::protobuf::MessageField<super::configuration::Controller>, - // @@protoc_insertion_point(field:netsim.config.Bluetooth.address_reuse) - pub address_reuse: ::std::option::Option<bool>, + // @@protoc_insertion_point(field:netsim.config.Bluetooth.disable_address_reuse) + pub disable_address_reuse: ::std::option::Option<bool>, + // @@protoc_insertion_point(field:netsim.config.Bluetooth.test_beacons) + pub test_beacons: ::std::option::Option<bool>, // special fields // @@protoc_insertion_point(special_field:netsim.config.Bluetooth.special_fields) pub special_fields: ::protobuf::SpecialFields, @@ -742,7 +744,7 @@ impl Bluetooth { } fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { - let mut fields = ::std::vec::Vec::with_capacity(2); + let mut fields = ::std::vec::Vec::with_capacity(3); let mut oneofs = ::std::vec::Vec::with_capacity(0); fields.push(::protobuf::reflect::rt::v2::make_message_field_accessor::<_, super::configuration::Controller>( "properties", @@ -750,9 +752,14 @@ impl Bluetooth { |m: &mut Bluetooth| { &mut m.properties }, )); fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( - "address_reuse", - |m: &Bluetooth| { &m.address_reuse }, - |m: &mut Bluetooth| { &mut m.address_reuse }, + "disable_address_reuse", + |m: &Bluetooth| { &m.disable_address_reuse }, + |m: &mut Bluetooth| { &mut m.disable_address_reuse }, + )); + fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( + "test_beacons", + |m: &Bluetooth| { &m.test_beacons }, + |m: &mut Bluetooth| { &mut m.test_beacons }, )); ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<Bluetooth>( "Bluetooth", @@ -776,7 +783,10 @@ impl ::protobuf::Message for Bluetooth { ::protobuf::rt::read_singular_message_into_field(is, &mut self.properties)?; }, 16 => { - self.address_reuse = ::std::option::Option::Some(is.read_bool()?); + self.disable_address_reuse = ::std::option::Option::Some(is.read_bool()?); + }, + 24 => { + self.test_beacons = ::std::option::Option::Some(is.read_bool()?); }, tag => { ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; @@ -794,7 +804,10 @@ impl ::protobuf::Message for Bluetooth { let len = v.compute_size(); my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len; } - if let Some(v) = self.address_reuse { + if let Some(v) = self.disable_address_reuse { + my_size += 1 + 1; + } + if let Some(v) = self.test_beacons { my_size += 1 + 1; } my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); @@ -806,9 +819,12 @@ impl ::protobuf::Message for Bluetooth { if let Some(v) = self.properties.as_ref() { ::protobuf::rt::write_message_field_with_cached_size(1, v, os)?; } - if let Some(v) = self.address_reuse { + if let Some(v) = self.disable_address_reuse { os.write_bool(2, v)?; } + if let Some(v) = self.test_beacons { + os.write_bool(3, v)?; + } os.write_unknown_fields(self.special_fields.unknown_fields())?; ::std::result::Result::Ok(()) } @@ -827,14 +843,16 @@ impl ::protobuf::Message for Bluetooth { fn clear(&mut self) { self.properties.clear(); - self.address_reuse = ::std::option::Option::None; + self.disable_address_reuse = ::std::option::Option::None; + self.test_beacons = ::std::option::Option::None; self.special_fields.clear(); } fn default_instance() -> &'static Bluetooth { static instance: Bluetooth = Bluetooth { properties: ::protobuf::MessageField::none(), - address_reuse: ::std::option::Option::None, + disable_address_reuse: ::std::option::Option::None, + test_beacons: ::std::option::Option::None, special_fields: ::protobuf::SpecialFields::new(), }; &instance @@ -859,6 +877,128 @@ impl ::protobuf::reflect::ProtobufValue for Bluetooth { } #[derive(PartialEq,Clone,Default,Debug)] +// @@protoc_insertion_point(message:netsim.config.Capture) +pub struct Capture { + // message fields + // @@protoc_insertion_point(field:netsim.config.Capture.enabled) + pub enabled: ::std::option::Option<bool>, + // special fields + // @@protoc_insertion_point(special_field:netsim.config.Capture.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a Capture { + fn default() -> &'a Capture { + <Capture as ::protobuf::Message>::default_instance() + } +} + +impl Capture { + pub fn new() -> Capture { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>( + "enabled", + |m: &Capture| { &m.enabled }, + |m: &mut Capture| { &mut m.enabled }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<Capture>( + "Capture", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for Capture { + const NAME: &'static str = "Capture"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 8 => { + self.enabled = ::std::option::Option::Some(is.read_bool()?); + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if let Some(v) = self.enabled { + my_size += 1 + 1; + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if let Some(v) = self.enabled { + os.write_bool(1, v)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> Capture { + Capture::new() + } + + fn clear(&mut self) { + self.enabled = ::std::option::Option::None; + self.special_fields.clear(); + } + + fn default_instance() -> &'static Capture { + static instance: Capture = Capture { + enabled: ::std::option::Option::None, + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for Capture { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("Capture").unwrap()).clone() + } +} + +impl ::std::fmt::Display for Capture { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for Capture { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>; +} + +#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:netsim.config.Config) pub struct Config { // message fields @@ -866,6 +1006,8 @@ pub struct Config { pub bluetooth: ::protobuf::MessageField<Bluetooth>, // @@protoc_insertion_point(field:netsim.config.Config.wifi) pub wifi: ::protobuf::MessageField<WiFi>, + // @@protoc_insertion_point(field:netsim.config.Config.capture) + pub capture: ::protobuf::MessageField<Capture>, // special fields // @@protoc_insertion_point(special_field:netsim.config.Config.special_fields) pub special_fields: ::protobuf::SpecialFields, @@ -883,7 +1025,7 @@ impl Config { } fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { - let mut fields = ::std::vec::Vec::with_capacity(2); + let mut fields = ::std::vec::Vec::with_capacity(3); let mut oneofs = ::std::vec::Vec::with_capacity(0); fields.push(::protobuf::reflect::rt::v2::make_message_field_accessor::<_, Bluetooth>( "bluetooth", @@ -895,6 +1037,11 @@ impl Config { |m: &Config| { &m.wifi }, |m: &mut Config| { &mut m.wifi }, )); + fields.push(::protobuf::reflect::rt::v2::make_message_field_accessor::<_, Capture>( + "capture", + |m: &Config| { &m.capture }, + |m: &mut Config| { &mut m.capture }, + )); ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<Config>( "Config", fields, @@ -919,6 +1066,9 @@ impl ::protobuf::Message for Config { 18 => { ::protobuf::rt::read_singular_message_into_field(is, &mut self.wifi)?; }, + 26 => { + ::protobuf::rt::read_singular_message_into_field(is, &mut self.capture)?; + }, tag => { ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; }, @@ -939,6 +1089,10 @@ impl ::protobuf::Message for Config { let len = v.compute_size(); my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len; } + if let Some(v) = self.capture.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len; + } my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); self.special_fields.cached_size().set(my_size as u32); my_size @@ -951,6 +1105,9 @@ impl ::protobuf::Message for Config { if let Some(v) = self.wifi.as_ref() { ::protobuf::rt::write_message_field_with_cached_size(2, v, os)?; } + if let Some(v) = self.capture.as_ref() { + ::protobuf::rt::write_message_field_with_cached_size(3, v, os)?; + } os.write_unknown_fields(self.special_fields.unknown_fields())?; ::std::result::Result::Ok(()) } @@ -970,6 +1127,7 @@ impl ::protobuf::Message for Config { fn clear(&mut self) { self.bluetooth.clear(); self.wifi.clear(); + self.capture.clear(); self.special_fields.clear(); } @@ -977,6 +1135,7 @@ impl ::protobuf::Message for Config { static instance: Config = Config { bluetooth: ::protobuf::MessageField::none(), wifi: ::protobuf::MessageField::none(), + capture: ::protobuf::MessageField::none(), special_fields: ::protobuf::SpecialFields::new(), }; &instance @@ -1020,13 +1179,17 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x18\x03\x20\x01(\tR\x06passwdB\x0b\n\t_disabled\"\x90\x01\n\x04WiFi\x12\ @\n\rslirp_options\x18\x01\x20\x01(\x0b2\x1b.netsim.config.SlirpOptionsR\ \x0cslirpOptions\x12F\n\x0fhostapd_options\x18\x02\x20\x01(\x0b2\x1d.net\ - sim.config.HostapdOptionsR\x0ehostapdOptions\"\xa0\x01\n\tBluetooth\x12H\ + sim.config.HostapdOptionsR\x0ehostapdOptions\"\xf0\x01\n\tBluetooth\x12H\ \n\nproperties\x18\x01\x20\x01(\x0b2#.rootcanal.configuration.Controller\ - H\0R\nproperties\x88\x01\x01\x12(\n\raddress_reuse\x18\x02\x20\x01(\x08H\ - \x01R\x0caddressReuse\x88\x01\x01B\r\n\x0b_propertiesB\x10\n\x0e_address\ - _reuse\"i\n\x06Config\x126\n\tbluetooth\x18\x01\x20\x01(\x0b2\x18.netsim\ - .config.BluetoothR\tbluetooth\x12'\n\x04wifi\x18\x02\x20\x01(\x0b2\x13.n\ - etsim.config.WiFiR\x04wifib\x06proto3\ + H\0R\nproperties\x88\x01\x01\x127\n\x15disable_address_reuse\x18\x02\x20\ + \x01(\x08H\x01R\x13disableAddressReuse\x88\x01\x01\x12&\n\x0ctest_beacon\ + s\x18\x03\x20\x01(\x08H\x02R\x0btestBeacons\x88\x01\x01B\r\n\x0b_propert\ + iesB\x18\n\x16_disable_address_reuseB\x0f\n\r_test_beacons\"4\n\x07Captu\ + re\x12\x1d\n\x07enabled\x18\x01\x20\x01(\x08H\0R\x07enabled\x88\x01\x01B\ + \n\n\x08_enabled\"\x9b\x01\n\x06Config\x126\n\tbluetooth\x18\x01\x20\x01\ + (\x0b2\x18.netsim.config.BluetoothR\tbluetooth\x12'\n\x04wifi\x18\x02\ + \x20\x01(\x0b2\x13.netsim.config.WiFiR\x04wifi\x120\n\x07capture\x18\x03\ + \x20\x01(\x0b2\x16.netsim.config.CaptureR\x07captureb\x06proto3\ "; /// `FileDescriptorProto` object which was a source for this generated file @@ -1045,11 +1208,12 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor { let generated_file_descriptor = generated_file_descriptor_lazy.get(|| { let mut deps = ::std::vec::Vec::with_capacity(1); deps.push(super::configuration::file_descriptor().clone()); - let mut messages = ::std::vec::Vec::with_capacity(5); + let mut messages = ::std::vec::Vec::with_capacity(6); messages.push(SlirpOptions::generated_message_descriptor_data()); messages.push(HostapdOptions::generated_message_descriptor_data()); messages.push(WiFi::generated_message_descriptor_data()); messages.push(Bluetooth::generated_message_descriptor_data()); + messages.push(Capture::generated_message_descriptor_data()); messages.push(Config::generated_message_descriptor_data()); let mut enums = ::std::vec::Vec::with_capacity(0); ::protobuf::reflect::GeneratedFileDescriptor::new_generated( diff --git a/src/backend/grpc_server.cc b/src/backend/grpc_server.cc index d995156..39ce7a4 100644 --- a/src/backend/grpc_server.cc +++ b/src/backend/grpc_server.cc @@ -47,7 +47,7 @@ using Stream = using netsim::startup::Chip; -// Mapping from <chip kind, facade id> to streams. +// Mapping from chip_id to streams. std::unordered_map<uint32_t, Stream *> chip_id_to_stream; // Libslirp is not thread safe. Use a lock to prevent concurrent access to @@ -114,13 +114,12 @@ class ServiceImpl final : public packet::PacketStreamer::Service { } uint32_t device_id = result->GetDeviceId(); uint32_t chip_id = result->GetChipId(); - uint32_t rootcanal_id = result->GetFacadeId(); BtsLogInfo( - "grpc_server: adding chip - chip_id: %d, rootcanal_id: %d, " + "grpc_server: adding chip - chip_id: %d, " "device_name: " "%s", - chip_id, rootcanal_id, device_name.c_str()); + chip_id, device_name.c_str()); // connect packet responses from chip facade to the peer chip_id_to_stream[chip_id] = stream; netsim::transport::RegisterGrpcTransport(chip_id); @@ -134,10 +133,10 @@ class ServiceImpl final : public packet::PacketStreamer::Service { netsim::device::RemoveChipCxx(device_id, chip_id); BtsLogInfo( - "grpc_server: removing chip - chip_id: %d, rootcanal_id: %d, " + "grpc_server: removing chip - chip_id: %d, " "device_name: " "%s", - chip_id, rootcanal_id, device_name.c_str()); + chip_id, device_name.c_str()); return ::grpc::Status::OK; } diff --git a/src/hci/bluetooth_facade.cc b/src/hci/bluetooth_facade.cc index b97eb42..5b25399 100644 --- a/src/hci/bluetooth_facade.cc +++ b/src/hci/bluetooth_facade.cc @@ -198,7 +198,7 @@ void SetUpTestChannel(uint16_t instance_num) { // Initialize the rootcanal library. void Start(const rust::Slice<::std::uint8_t const> proto_bytes, - uint16_t instance_num, bool disable_address_reuse) { + uint16_t instance_num) { if (gStarted) return; // output is to a file, so no color wanted @@ -238,8 +238,10 @@ void Start(const rust::Slice<::std::uint8_t const> proto_bytes, rootcanal::Phy::Type /* phy_type */) { return nullptr; }); // Disable Address Reuse if '--disable_address_reuse' flag is true - // TODO: once config files are active, use the value from config proto - gTestModel->SetReuseDeviceAddresses(!disable_address_reuse); + // Enable Address Reuse if 'address_reuse' is true + if (config.has_disable_address_reuse()) { + gTestModel->SetReuseDeviceAddresses(!config.disable_address_reuse()); + } // NOTE: 0:BR_EDR, 1:LOW_ENERGY. The order is used by bluetooth CTS. phy_classic_index_ = gTestModel->AddPhy(rootcanal::Phy::Type::BR_EDR); @@ -275,7 +277,7 @@ void PatchPhy(int device_id, bool isAddToPhy, bool isLowEnergy) { class ChipInfo { public: - uint32_t simulation_device; + uint32_t chip_id; std::shared_ptr<model::Chip::Bluetooth> model; int le_tx_count = 0; int classic_tx_count = 0; @@ -284,14 +286,13 @@ class ChipInfo { std::shared_ptr<rootcanal::configuration::Controller> controller_proto; std::unique_ptr<rootcanal::ControllerProperties> controller_properties; - ChipInfo(uint32_t simulation_device, - std::shared_ptr<model::Chip::Bluetooth> model) - : simulation_device(simulation_device), model(model) {} + ChipInfo(uint32_t chip_id, std::shared_ptr<model::Chip::Bluetooth> model) + : chip_id(chip_id), model(model) {} ChipInfo( - uint32_t simulation_device, std::shared_ptr<model::Chip::Bluetooth> model, + uint32_t chip_id, std::shared_ptr<model::Chip::Bluetooth> model, std::shared_ptr<rootcanal::configuration::Controller> controller_proto, std::unique_ptr<rootcanal::ControllerProperties> controller_properties) - : simulation_device(simulation_device), + : chip_id(chip_id), model(model), controller_proto(std::move(controller_proto)), controller_properties(std::move(controller_properties)) {} @@ -364,8 +365,7 @@ void Remove(uint32_t id) { // Rename AddChip(model::Chip, device, transport) -uint32_t Add(uint32_t simulation_device, uint32_t chip_id, - const std::string &address_string, +uint32_t Add(uint32_t chip_id, const std::string &address_string, const rust::Slice<::std::uint8_t const> controller_proto_bytes) { auto transport = std::make_shared<HciPacketTransport>(chip_id, gAsyncManager); @@ -376,8 +376,8 @@ uint32_t Add(uint32_t simulation_device, uint32_t chip_id, rootcanal::configuration::Controller custom_proto; custom_proto.ParseFromArray(controller_proto_bytes.data(), controller_proto_bytes.size()); - BtsLogInfo("device_id: %d has rootcanal Controller configuration: %s", - simulation_device, custom_proto.ShortDebugString().c_str()); + BtsLogInfo("chip_id: %d has rootcanal Controller configuration: %s", + chip_id, custom_proto.ShortDebugString().c_str()); // When emulators restore from a snapshot the PacketStreamer connection to // netsim is recreated with a new (uninitialized) Rootcanal device. However @@ -414,17 +414,16 @@ uint32_t Add(uint32_t simulation_device, uint32_t chip_id, auto rootcanal_id = rootcanal_id_future.get(); HciPacketTransport::Add(rootcanal_id, transport); - BtsLogInfo("Creating HCI rootcanal_id: %d for device_id: %d", rootcanal_id, - simulation_device); + BtsLogInfo("Creating HCI rootcanal_id: %d for chip_id: %d", rootcanal_id, + chip_id); auto model = std::make_shared<model::Chip::Bluetooth>(); model->mutable_classic()->set_state(model::State::ON); model->mutable_low_energy()->set_state(model::State::ON); - id_to_chip_info_.emplace( - rootcanal_id, - std::make_shared<ChipInfo>(simulation_device, model, controller_proto, - std::move(controller_properties))); + id_to_chip_info_.emplace(rootcanal_id, std::make_shared<ChipInfo>( + chip_id, model, controller_proto, + std::move(controller_properties))); return rootcanal_id; } @@ -433,9 +432,8 @@ void RemoveRustDevice(uint32_t rootcanal_id) { } rust::Box<AddRustDeviceResult> AddRustDevice( - uint32_t simulation_device, - rust::Box<DynRustBluetoothChipCallbacks> callbacks, const std::string &type, - const std::string &address) { + uint32_t chip_id, rust::Box<DynRustBluetoothChipCallbacks> callbacks, + const std::string &type, const std::string &address) { auto rust_device = std::make_shared<RustDevice>(std::move(callbacks), type, address); @@ -448,8 +446,8 @@ rust::Box<AddRustDeviceResult> AddRustDevice( auto model = std::make_shared<model::Chip::Bluetooth>(); // Only enable ble for beacon. model->mutable_low_energy()->set_state(model::State::ON); - id_to_chip_info_.emplace( - rootcanal_id, std::make_shared<ChipInfo>(simulation_device, model)); + id_to_chip_info_.emplace(rootcanal_id, + std::make_shared<ChipInfo>(chip_id, model)); return CreateAddRustDeviceResult( rootcanal_id, std::make_unique<RustBluetoothChip>(rust_device)); } @@ -496,8 +494,8 @@ int8_t SimComputeRssi(int send_id, int recv_id, int8_t tx_power) { #endif return tx_power; } - auto a = id_to_chip_info_[send_id]->simulation_device; - auto b = id_to_chip_info_[recv_id]->simulation_device; + auto a = id_to_chip_info_[send_id]->chip_id; + auto b = id_to_chip_info_[recv_id]->chip_id; auto distance = netsim::device::GetDistanceCxx(a, b); return netsim::DistanceToRssi(tx_power, distance); } diff --git a/src/hci/bluetooth_facade.h b/src/hci/bluetooth_facade.h index b8998a2..fa6c730 100644 --- a/src/hci/bluetooth_facade.h +++ b/src/hci/bluetooth_facade.h @@ -39,21 +39,19 @@ void Reset(uint32_t); void Remove(uint32_t); void Patch(uint32_t, const model::Chip::Bluetooth &); model::Chip::Bluetooth Get(uint32_t); -uint32_t Add(uint32_t simulation_device, uint32_t chip_id, - const std::string &address_string, +uint32_t Add(uint32_t chip_id, const std::string &address_string, const rust::Slice<::std::uint8_t const> controller_proto_bytes); rust::Box<AddRustDeviceResult> AddRustDevice( - uint32_t simulation_device, - rust::Box<DynRustBluetoothChipCallbacks> callbacks, const std::string &type, - const std::string &address); + uint32_t chip_id, rust::Box<DynRustBluetoothChipCallbacks> callbacks, + const std::string &type, const std::string &address); void SetRustDeviceAddress( uint32_t rootcanal_id, std::array<uint8_t, rootcanal::Address::kLength> address); void RemoveRustDevice(uint32_t rootcanal_id); void Start(const rust::Slice<::std::uint8_t const> proto_bytes, - uint16_t instance_num, bool disable_address_reuse); + uint16_t instance_num); void Stop(); // Cxx functions for rust ffi. |