aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-17 02:16:24 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-17 02:16:24 +0000
commit3417cf89494be9900c2a4d0ab9a70386e25c0bfa (patch)
treec183e84d46d6b3fca2929cadaa058d22738ac109
parentc8ec243e9a5ab980573c72b44d6b9bbdd8b44569 (diff)
parenta476e3bfdc11d50e47098682b7490970115f6b11 (diff)
downloadnetsim-3417cf89494be9900c2a4d0ab9a70386e25c0bfa.tar.gz
Snap for 11228863 from a476e3bfdc11d50e47098682b7490970115f6b11 to emu-34-release
Change-Id: Ifd0669072c137732cafc376404791038fc864f00
-rw-r--r--Android.bp4
-rw-r--r--TEST_MAPPING16
-rw-r--r--pdl/ieee80211.pdl79
-rw-r--r--proto/netsim/config.proto12
-rw-r--r--rust/cli/Cargo.toml2
-rw-r--r--rust/daemon/Cargo.toml2
-rw-r--r--rust/daemon/src/bluetooth/beacon.rs10
-rw-r--r--rust/daemon/src/bluetooth/chip.rs6
-rw-r--r--rust/daemon/src/bluetooth/mocked.rs1
-rw-r--r--rust/daemon/src/captures/capture.rs55
-rw-r--r--rust/daemon/src/devices/chip.rs211
-rw-r--r--rust/daemon/src/devices/device.rs4
-rw-r--r--rust/daemon/src/devices/devices_handler.rs332
-rw-r--r--rust/daemon/src/echip/ble_beacon.rs33
-rw-r--r--rust/daemon/src/echip/bluetooth.rs35
-rw-r--r--rust/daemon/src/echip/emulated_chip.rs53
-rw-r--r--rust/daemon/src/echip/mocked.rs36
-rw-r--r--rust/daemon/src/echip/mod.rs4
-rw-r--r--rust/daemon/src/echip/packet.rs32
-rw-r--r--rust/daemon/src/echip/wifi.rs31
-rw-r--r--rust/daemon/src/events.rs98
-rw-r--r--rust/daemon/src/ffi.rs13
-rw-r--r--rust/daemon/src/rust_main.rs53
-rw-r--r--rust/daemon/src/session.rs17
-rw-r--r--rust/daemon/src/transport/fd.rs11
-rw-r--r--rust/daemon/src/version.rs2
-rw-r--r--rust/daemon/src/wifi/frame.rs14
-rw-r--r--rust/daemon/src/wifi/ieee80211.rs112
-rw-r--r--rust/daemon/src/wifi/medium.rs42
-rw-r--r--rust/daemon/src/wifi/mod.rs1
-rw-r--r--rust/daemon/src/wifi/packets.rs8
-rw-r--r--rust/proto/src/config.rs202
-rw-r--r--src/backend/grpc_server.cc11
-rw-r--r--src/hci/bluetooth_facade.cc50
-rw-r--r--src/hci/bluetooth_facade.h10
35 files changed, 1149 insertions, 453 deletions
diff --git a/Android.bp b/Android.bp
index 9d36918..512e8d2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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, &params.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, &params.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.