diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-14 00:25:15 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-14 00:25:15 +0000 |
commit | 5658c3db12895bca6fa218737ee2933a6d615ac1 (patch) | |
tree | c56d4d48b2ed65ec2b179b0312d2815453037fdb | |
parent | adb07458fca5d3a35632bf3fd3a58322e235c42d (diff) | |
parent | 154857395c25564b37c80e3767a8ca9e4136b843 (diff) | |
download | netsim-5658c3db12895bca6fa218737ee2933a6d615ac1.tar.gz |
Snap for 11216811 from 154857395c25564b37c80e3767a8ca9e4136b843 to 24Q1-release
Change-Id: I46a6ccc06bade41b8e9cd28a9932a4c7c6488813
-rw-r--r-- | TEST_MAPPING | 3 | ||||
-rw-r--r-- | pdl/ieee80211.pdl | 79 | ||||
-rw-r--r-- | rust/daemon/src/bluetooth/beacon.rs | 10 | ||||
-rw-r--r-- | rust/daemon/src/bluetooth/chip.rs | 6 | ||||
-rw-r--r-- | rust/daemon/src/bluetooth/mocked.rs | 1 | ||||
-rw-r--r-- | rust/daemon/src/devices/chip.rs | 203 | ||||
-rw-r--r-- | rust/daemon/src/devices/device.rs | 2 | ||||
-rw-r--r-- | rust/daemon/src/devices/devices_handler.rs | 50 | ||||
-rw-r--r-- | rust/daemon/src/echip/ble_beacon.rs | 9 | ||||
-rw-r--r-- | rust/daemon/src/echip/bluetooth.rs | 13 | ||||
-rw-r--r-- | rust/daemon/src/echip/emulated_chip.rs | 19 | ||||
-rw-r--r-- | rust/daemon/src/echip/mocked.rs | 21 | ||||
-rw-r--r-- | rust/daemon/src/echip/wifi.rs | 11 | ||||
-rw-r--r-- | rust/daemon/src/ffi.rs | 9 | ||||
-rw-r--r-- | rust/daemon/src/wifi/frame.rs | 2 | ||||
-rw-r--r-- | rust/daemon/src/wifi/ieee80211.rs | 112 | ||||
-rw-r--r-- | rust/daemon/src/wifi/mod.rs | 1 | ||||
-rw-r--r-- | rust/daemon/src/wifi/packets.rs | 8 | ||||
-rw-r--r-- | src/hci/bluetooth_facade.cc | 42 | ||||
-rw-r--r-- | src/hci/bluetooth_facade.h | 8 |
20 files changed, 483 insertions, 126 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING index e49a4a3b..454a8df0 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -10,6 +10,9 @@ "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 f94a6b21..3e28f60d 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/rust/daemon/src/bluetooth/beacon.rs b/rust/daemon/src/bluetooth/beacon.rs index 13d8ef8c..77c69648 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 faaecbe1..add0a865 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 41e757a4..68a60a67 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/devices/chip.rs b/rust/daemon/src/devices/chip.rs index 1979abde..2008257d 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(), @@ -138,8 +163,174 @@ impl Chip { } } -/// 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 8b46061d..fc889833 100644 --- a/rust/daemon/src/devices/device.rs +++ b/rust/daemon/src/devices/device.rs @@ -186,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 400420bf..dc96d5a7 100644 --- a/rust/daemon/src/devices/devices_handler.rs +++ b/rust/daemon/src/devices/devices_handler.rs @@ -144,7 +144,7 @@ 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 emulated_chip = echip::new(echip_create_params, chip_id); // Lock Device Resource { let devices_arc = get_devices(); @@ -562,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)) @@ -1434,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() diff --git a/rust/daemon/src/echip/ble_beacon.rs b/rust/daemon/src/echip/ble_beacon.rs index 53fddc1b..0b8dd9f6 100644 --- a/rust/daemon/src/echip/ble_beacon.rs +++ b/rust/daemon/src/echip/ble_beacon.rs @@ -14,7 +14,6 @@ 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, info}; @@ -94,12 +93,8 @@ impl EmulatedChip for BleBeacon { } /// Create a new Emulated BleBeacon Chip -pub fn new( - params: &CreateParams, - device_id: DeviceIdentifier, - chip_id: ChipIdentifier, -) -> SharedEmulatedChip { - match ble_beacon_add(device_id, params.device_name.clone(), chip_id, ¶ms.chip_proto) { +pub fn new(params: &CreateParams, chip_id: ChipIdentifier) -> SharedEmulatedChip { + match ble_beacon_add(params.device_name.clone(), chip_id, ¶ms.chip_proto) { Ok(facade_id) => { info!("BleBeacon EmulatedChip created with facade_id: {facade_id} chip_id: {chip_id}"); SharedEmulatedChip(Arc::new(Mutex::new(Box::new(BleBeacon { facade_id, chip_id })))) diff --git a/rust/daemon/src/echip/bluetooth.rs b/rust/daemon/src/echip/bluetooth.rs index abe77c3d..1661128f 100644 --- a/rust/daemon/src/echip/bluetooth.rs +++ b/rust/daemon/src/echip/bluetooth.rs @@ -13,11 +13,8 @@ // 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; @@ -103,11 +100,7 @@ impl EmulatedChip for Bluetooth { } /// 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()); @@ -115,7 +108,7 @@ 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 }; SharedEmulatedChip(Arc::new(Mutex::new(Box::new(echip)))) diff --git a/rust/daemon/src/echip/emulated_chip.rs b/rust/daemon/src/echip/emulated_chip.rs index e9c14f61..27970a22 100644 --- a/rust/daemon/src/echip/emulated_chip.rs +++ b/rust/daemon/src/echip/emulated_chip.rs @@ -24,7 +24,7 @@ use netsim_proto::model::Chip as ProtoChip; use netsim_proto::stats::NetsimRadioStats as ProtoRadioStats; use crate::{ - devices::{chip::ChipIdentifier, device::DeviceIdentifier}, + devices::chip::ChipIdentifier, echip::{ble_beacon, mocked}, }; @@ -116,21 +116,17 @@ pub fn remove(chip_id: ChipIdentifier) -> Option<SharedEmulatedChip> { /// 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,9 +146,8 @@ 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); + 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 9c5cf47e..00e49153 100644 --- a/rust/daemon/src/echip/mocked.rs +++ b/rust/daemon/src/echip/mocked.rs @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -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, Mutex}; @@ -37,7 +38,9 @@ impl EmulatedChip for Mock { 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(&mut self, chip: &ProtoChip) {} @@ -45,7 +48,15 @@ impl EmulatedChip for Mock { 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 { @@ -54,6 +65,6 @@ impl EmulatedChip for Mock { } /// Create a new MockedChip -pub fn new(create_params: &CreateParams, device_id: DeviceIdentifier) -> SharedEmulatedChip { +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/wifi.rs b/rust/daemon/src/echip/wifi.rs index f9e81a35..2dba81ae 100644 --- a/rust/daemon/src/echip/wifi.rs +++ b/rust/daemon/src/echip/wifi.rs @@ -13,12 +13,9 @@ // limitations under the License. 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; @@ -84,11 +81,7 @@ impl EmulatedChip for Wifi { } /// 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 }; diff --git a/rust/daemon/src/ffi.rs b/rust/daemon/src/ffi.rs index 2da65992..19763f21 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, diff --git a/rust/daemon/src/wifi/frame.rs b/rust/daemon/src/wifi/frame.rs index 7737ae50..9a194362 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; diff --git a/rust/daemon/src/wifi/ieee80211.rs b/rust/daemon/src/wifi/ieee80211.rs index d5a4f1e4..7e501b8e 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/mod.rs b/rust/daemon/src/wifi/mod.rs index 43c62605..8891cce0 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 934b707d..a3f99870 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/src/hci/bluetooth_facade.cc b/src/hci/bluetooth_facade.cc index b97eb42b..7195f464 100644 --- a/src/hci/bluetooth_facade.cc +++ b/src/hci/bluetooth_facade.cc @@ -275,7 +275,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 +284,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 +363,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 +374,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 +412,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 +430,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 +444,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 +492,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 b8998a27..bb84e0db 100644 --- a/src/hci/bluetooth_facade.h +++ b/src/hci/bluetooth_facade.h @@ -39,14 +39,12 @@ 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); |