1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! Netsim daemon cxx libraries.
16
17 use crate::bluetooth::chip::{
18 create_add_rust_device_result, AddRustDeviceResult, RustBluetoothChipCallbacks,
19 };
20
21 use crate::devices::devices_handler::get_distance_cxx;
22 use crate::ranging::*;
23 use crate::wireless::{
24 bluetooth::report_invalid_packet_cxx, handle_request_cxx, handle_response_cxx,
25 };
26
27 #[allow(unsafe_op_in_unsafe_fn)]
28 #[cxx::bridge(namespace = "netsim::wireless")]
29 pub mod ffi_wireless {
30 extern "Rust" {
31 #[cxx_name = HandleRequestCxx]
handle_request_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8)32 fn handle_request_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8);
33
34 #[cxx_name = HandleResponse]
handle_response_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8)35 fn handle_response_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8);
36 }
37 }
38
39 #[allow(unsafe_op_in_unsafe_fn)]
40 #[cxx::bridge(namespace = "netsim::transport")]
41 pub mod ffi_transport {
42 unsafe extern "C++" {
43 // Grpc client.
44 // Expose functions in Cuttlefish only, because it's only used by CVDs and it's
45 // unable to pass function pointers on Windows.
46 #[cfg(feature = "cuttlefish")]
47 include!("backend/grpc_client.h");
48
49 #[allow(dead_code)]
50 #[rust_name = stream_packets]
51 #[namespace = "netsim::backend::client"]
52 #[cfg(feature = "cuttlefish")]
StreamPackets(server: &String) -> u3253 fn StreamPackets(server: &String) -> u32;
54
55 #[allow(dead_code)]
56 #[rust_name = read_packet_response_loop]
57 #[namespace = "netsim::backend::client"]
58 #[cfg(feature = "cuttlefish")]
ReadPacketResponseLoop( stream_id: u32, read_fn: fn(stream_id: u32, proto_bytes: &[u8]), ) -> bool59 fn ReadPacketResponseLoop(
60 stream_id: u32,
61 read_fn: fn(stream_id: u32, proto_bytes: &[u8]),
62 ) -> bool;
63
64 #[allow(dead_code)]
65 #[rust_name = write_packet_request]
66 #[cfg(feature = "cuttlefish")]
67 #[namespace = "netsim::backend::client"]
WritePacketRequest(stream_id: u32, proto_bytes: &[u8]) -> bool68 fn WritePacketRequest(stream_id: u32, proto_bytes: &[u8]) -> bool;
69
70 }
71 }
72
73 #[allow(clippy::needless_maybe_sized)]
74 #[allow(unsafe_op_in_unsafe_fn)]
75 #[cxx::bridge(namespace = "netsim")]
76 pub mod ffi_bluetooth {
77 extern "Rust" {
78 // Rust Bluetooth device.
79 #[namespace = "netsim::hci::facade"]
80 type DynRustBluetoothChipCallbacks;
81
82 #[cxx_name = Tick]
83 #[namespace = "netsim::hci::facade"]
tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks)84 fn tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks);
85
86 #[cxx_name = ReceiveLinkLayerPacket]
87 #[namespace = "netsim::hci::facade"]
receive_link_layer_packet( dyn_callbacks: &mut DynRustBluetoothChipCallbacks, source_address: String, destination_address: String, packet_type: u8, packet: &[u8], )88 fn receive_link_layer_packet(
89 dyn_callbacks: &mut DynRustBluetoothChipCallbacks,
90 source_address: String,
91 destination_address: String,
92 packet_type: u8,
93 packet: &[u8],
94 );
95
96 // Bluetooth facade.
97 #[namespace = "netsim::hci::facade"]
98 type AddRustDeviceResult;
99 #[cxx_name = "CreateAddRustDeviceResult"]
100 #[namespace = "netsim::hci"]
create_add_rust_device_result( facade_id: u32, rust_chip: UniquePtr<RustBluetoothChip>, ) -> Box<AddRustDeviceResult>101 fn create_add_rust_device_result(
102 facade_id: u32,
103 rust_chip: UniquePtr<RustBluetoothChip>,
104 ) -> Box<AddRustDeviceResult>;
105
106 // Rust Invalid Packet Report
107 #[cxx_name = "ReportInvalidPacket"]
108 #[namespace = "netsim::hci::facade"]
report_invalid_packet_cxx( rootcanal_id: u32, reason: i32, description: &CxxString, packet: &CxxVector<u8>, )109 fn report_invalid_packet_cxx(
110 rootcanal_id: u32,
111 reason: i32,
112 description: &CxxString,
113 packet: &CxxVector<u8>,
114 );
115 }
116
117 #[allow(dead_code)]
118 unsafe extern "C++" {
119 // Bluetooth facade.
120 include!("hci/hci_packet_hub.h");
121
122 #[rust_name = handle_bt_request]
123 #[namespace = "netsim::hci"]
HandleBtRequestCxx(rootcanal_id: u32, packet_type: u8, packet: &Vec<u8>)124 fn HandleBtRequestCxx(rootcanal_id: u32, packet_type: u8, packet: &Vec<u8>);
125
126 // Rust Bluetooth device.
127 include!("hci/rust_device.h");
128
129 #[namespace = "netsim::hci::facade"]
130 type RustBluetoothChip;
131 #[rust_name = send_link_layer_le_packet]
132 #[namespace = "netsim::hci::facade"]
SendLinkLayerLePacket(self: &RustBluetoothChip, packet: &[u8], tx_power: i8)133 fn SendLinkLayerLePacket(self: &RustBluetoothChip, packet: &[u8], tx_power: i8);
134
135 include!("hci/bluetooth_facade.h");
136
137 #[rust_name = bluetooth_get_cxx]
138 #[namespace = "netsim::hci::facade"]
GetCxx(rootcanal_id: u32) -> Vec<u8>139 pub fn GetCxx(rootcanal_id: u32) -> Vec<u8>;
140
141 #[rust_name = bluetooth_reset]
142 #[namespace = "netsim::hci::facade"]
Reset(rootcanal_id: u32)143 pub fn Reset(rootcanal_id: u32);
144
145 #[rust_name = bluetooth_remove]
146 #[namespace = "netsim::hci::facade"]
Remove(rootcanal_id: u32)147 pub fn Remove(rootcanal_id: u32);
148
149 #[rust_name = bluetooth_add]
150 #[namespace = "netsim::hci::facade"]
Add(chip_id: u32, address: &CxxString, controller_proto_bytes: &[u8]) -> u32151 pub fn Add(chip_id: u32, address: &CxxString, controller_proto_bytes: &[u8]) -> u32;
152
153 /*
154 From https://cxx.rs/binding/box.html#restrictions,
155 ```
156 If T is an opaque Rust type, the Rust type is required to be Sized i.e. size known at compile time. In the future we may introduce support for dynamically sized opaque Rust types.
157 ```
158
159 The workaround is using Box<dyn MyData> (fat pointer) as the opaque type.
160 Reference:
161 - Passing trait objects to C++. https://github.com/dtolnay/cxx/issues/665.
162 - Exposing trait methods to C++. https://github.com/dtolnay/cxx/issues/667
163 */
164 #[rust_name = bluetooth_add_rust_device]
165 #[namespace = "netsim::hci::facade"]
AddRustDevice( chip_id: u32, callbacks: Box<DynRustBluetoothChipCallbacks>, string_type: &CxxString, address: &CxxString, ) -> Box<AddRustDeviceResult>166 pub fn AddRustDevice(
167 chip_id: u32,
168 callbacks: Box<DynRustBluetoothChipCallbacks>,
169 string_type: &CxxString,
170 address: &CxxString,
171 ) -> Box<AddRustDeviceResult>;
172
173 /// The provided address must be 6 bytes in length
174 #[rust_name = bluetooth_set_rust_device_address]
175 #[namespace = "netsim::hci::facade"]
SetRustDeviceAddress(rootcanal_id: u32, address: [u8; 6])176 pub fn SetRustDeviceAddress(rootcanal_id: u32, address: [u8; 6]);
177
178 #[rust_name = bluetooth_remove_rust_device]
179 #[namespace = "netsim::hci::facade"]
RemoveRustDevice(rootcanal_id: u32)180 pub fn RemoveRustDevice(rootcanal_id: u32);
181
182 #[rust_name = bluetooth_start]
183 #[namespace = "netsim::hci::facade"]
Start(proto_bytes: &[u8], instance_num: u16)184 pub fn Start(proto_bytes: &[u8], instance_num: u16);
185
186 #[rust_name = bluetooth_stop]
187 #[namespace = "netsim::hci::facade"]
Stop()188 pub fn Stop();
189
190 #[rust_name = add_device_to_phy]
191 #[namespace = "netsim::hci::facade"]
AddDeviceToPhy(rootcanal_id: u32, is_low_energy: bool)192 pub fn AddDeviceToPhy(rootcanal_id: u32, is_low_energy: bool);
193
194 #[rust_name = remove_device_from_phy]
195 #[namespace = "netsim::hci::facade"]
RemoveDeviceFromPhy(rootcanal_id: u32, is_low_energy: bool)196 pub fn RemoveDeviceFromPhy(rootcanal_id: u32, is_low_energy: bool);
197 }
198 }
199
200 #[allow(clippy::needless_maybe_sized)]
201 #[allow(unsafe_op_in_unsafe_fn)]
202 #[cxx::bridge(namespace = "netsim::device")]
203 pub mod ffi_devices {
204 extern "Rust" {
205 #[cxx_name = GetDistanceCxx]
get_distance_cxx(a: u32, b: u32) -> f32206 fn get_distance_cxx(a: u32, b: u32) -> f32;
207 }
208 }
209
210 #[allow(unsafe_op_in_unsafe_fn)]
211 #[cxx::bridge(namespace = "netsim")]
212 pub mod ffi_util {
213 extern "Rust" {
214 // Ranging
215
216 #[cxx_name = "DistanceToRssi"]
distance_to_rssi(tx_power: i8, distance: f32) -> i8217 fn distance_to_rssi(tx_power: i8, distance: f32) -> i8;
218 }
219
220 #[allow(dead_code)]
221 unsafe extern "C++" {
222
223 // Crash report.
224 include!("util/crash_report.h");
225
226 #[rust_name = set_up_crash_report]
227 #[namespace = "netsim"]
SetUpCrashReport()228 pub fn SetUpCrashReport();
229 }
230 }
231
232 // It's required so `RustBluetoothChip` can be sent between threads safely.
233 // Ref: How to use opaque types in threads? https://github.com/dtolnay/cxx/issues/1175
234 // SAFETY: Nothing in `RustBluetoothChip` depends on being run on a particular thread.
235 unsafe impl Send for ffi_bluetooth::RustBluetoothChip {}
236
237 type DynRustBluetoothChipCallbacks = Box<dyn RustBluetoothChipCallbacks>;
238
tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks)239 fn tick(dyn_callbacks: &mut DynRustBluetoothChipCallbacks) {
240 (**dyn_callbacks).tick();
241 }
242
receive_link_layer_packet( dyn_callbacks: &mut DynRustBluetoothChipCallbacks, source_address: String, destination_address: String, packet_type: u8, packet: &[u8], )243 fn receive_link_layer_packet(
244 dyn_callbacks: &mut DynRustBluetoothChipCallbacks,
245 source_address: String,
246 destination_address: String,
247 packet_type: u8,
248 packet: &[u8],
249 ) {
250 (**dyn_callbacks).receive_link_layer_packet(
251 source_address,
252 destination_address,
253 packet_type,
254 packet,
255 );
256 }
257