da14531: export C API from bitbox-da14531
What changed, and why it matters
This commit exposes a Rust Bluetooth Low Energy (BLE) chip control library to C code. It adds C-callable functions for powering down, resetting, setting product/name strings, and checking connection state. The change is primarily an interface/API export with no obvious security bug, but it introduces new unsafe C boundaries that must be used correctly by callers.
Review the C callers of these new FFI functions to ensure they validate pointers and buffer lifetimes before invocation. Consider adding null/length checks in the FFI boundary if not already present in callers. No immediate patch required for the commit itself.
Security signals we found
New unsafe extern "C" FFI functions added with raw pointer parameters
Pointer cast from RustByteQueue* to ByteQueue* without runtime type validation
C callers must guarantee validity of uart_out pointer and byte buffer lifetimes
No length validation change beyond existing assert(product.len() < 64)
Refactoring of string setters to byte-slice setters may broaden input surface
Evidence from the diff
The patch exports bitbox-da14531 Rust functions as #[unsafe(no_mangle)] extern "C" symbols: rust_da14531_power_down, rust_da14531_reset, rust_da14531_set_product, rust_da14531_set_name, and rust_da14531_get_connection_state. It adds util and bitbox-da14531 dependencies, updates cbindgen configuration, and refactors set_product/set_name to accept byte slices. Safety documentation is included for raw pointer and buffer lifetime requirements.
Changed components
src/rust/bitbox-da14531/src/lib.rssrc/rust/bitbox-da14531/Cargo.tomlsrc/rust/bitbox02-rust-c/src/lib.rssrc/rust/bitbox02-rust-c/Cargo.tomlsrc/rust/bitbox02-cbindgen.tomlsrc/rust/Cargo.locktest/simulator-graphical-bb03/Cargo.locktest/simulator-graphical/Cargo.lockInspect captured patch +72 / −5
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
index 6d88b61..2afd19d 100644
--- a/src/rust/Cargo.lock
+++ b/src/rust/Cargo.lock
@@ -114,6 +114,7 @@ dependencies = [
"bitbox-bytequeue",
"bitbox-framed-serial-link",
"hex_lit",
+ "util",
]
[[package]]
@@ -224,6 +225,7 @@ dependencies = [
"bip39",
"bitbox-aes",
"bitbox-bytequeue",
+ "bitbox-da14531",
"bitbox-framed-serial-link",
"bitbox-hal",
"bitbox02",
diff --git a/src/rust/bitbox-da14531/Cargo.toml b/src/rust/bitbox-da14531/Cargo.toml
index 3c909a0..b735332 100644
--- a/src/rust/bitbox-da14531/Cargo.toml
+++ b/src/rust/bitbox-da14531/Cargo.toml
@@ -10,6 +10,7 @@ license = "Apache-2.0"
[dependencies]
bitbox-framed-serial-link = { path = "../bitbox-framed-serial-link" }
bitbox-bytequeue = { path = "../bitbox-bytequeue" }
+util = { path = "../util" }
[dev-dependencies]
hex_lit = { workspace = true }
diff --git a/src/rust/bitbox-da14531/src/lib.rs b/src/rust/bitbox-da14531/src/lib.rs
index 5a266bf..bf3d4ac 100644
--- a/src/rust/bitbox-da14531/src/lib.rs
+++ b/src/rust/bitbox-da14531/src/lib.rs
@@ -5,8 +5,9 @@
extern crate alloc;
use alloc::vec;
use alloc::vec::Vec;
-use bitbox_bytequeue::ByteQueue;
+use bitbox_bytequeue::{ByteQueue, RustByteQueue};
use bitbox_framed_serial_link::{ProtocolPacketType, protocol_format};
+use util::bytes::Bytes;
const CTRL_CMD_DEVICE_NAME: u8 = 1;
const CTRL_CMD_BLE_STATUS: u8 = 5;
@@ -25,7 +26,11 @@ fn enqueue_ctrl_data(payload: &[u8], queue: &mut ByteQueue) {
/// Set the product string of the BLE chip. The product string must be smaller than 64 bytes.
pub fn set_product(product: &str, queue: &mut ByteQueue) {
- let product = product.as_bytes();
+ set_product_bytes(product.as_bytes(), queue);
+}
+
+/// Set the product string of the BLE chip. The product string must be smaller than 64 bytes.
+pub fn set_product_bytes(product: &[u8], queue: &mut ByteQueue) {
assert!(
product.len() < CTRL_PAYLOAD_MAX_LEN,
"product string too large"
@@ -39,9 +44,14 @@ pub fn set_product(product: &str, queue: &mut ByteQueue) {
/// Set the device name of the BLE chip.
pub fn set_name(name: &str, queue: &mut ByteQueue) {
+ set_name_bytes(name.as_bytes(), queue);
+}
+
+/// Set the device name of the BLE chip.
+pub fn set_name_bytes(name: &[u8], queue: &mut ByteQueue) {
let mut payload = Vec::with_capacity(1 + name.len());
payload.push(CTRL_CMD_DEVICE_NAME);
- payload.extend_from_slice(name.as_bytes());
+ payload.extend_from_slice(name);
enqueue_ctrl_data(&payload, queue);
}
@@ -60,6 +70,53 @@ pub fn get_connection_state(queue: &mut ByteQueue) {
enqueue_ctrl_data(&[CTRL_CMD_BLE_STATUS], queue);
}
+fn queue_from_ptr(uart_out: *mut RustByteQueue) -> *mut ByteQueue {
+ assert!(!uart_out.is_null());
+ uart_out.cast::<ByteQueue>()
+}
+
+/// # Safety
+///
+/// `uart_out` must point to a valid `RustByteQueue`.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn rust_da14531_power_down(uart_out: *mut RustByteQueue) {
+ power_down(unsafe { &mut *queue_from_ptr(uart_out) });
+}
+
+/// # Safety
+///
+/// `uart_out` must point to a valid `RustByteQueue`.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn rust_da14531_reset(uart_out: *mut RustByteQueue) {
+ reset(unsafe { &mut *queue_from_ptr(uart_out) });
+}
+
+/// # Safety
+///
+/// `product` must reference a valid byte buffer for the duration of this call.
+/// `uart_out` must point to a valid `RustByteQueue`.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn rust_da14531_set_product(product: Bytes, uart_out: *mut RustByteQueue) {
+ set_product_bytes(product.as_ref(), unsafe { &mut *queue_from_ptr(uart_out) });
+}
+
+/// # Safety
+///
+/// `name` must reference a valid byte buffer for the duration of this call.
+/// `uart_out` must point to a valid `RustByteQueue`.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn rust_da14531_set_name(name: Bytes, uart_out: *mut RustByteQueue) {
+ set_name_bytes(name.as_ref(), unsafe { &mut *queue_from_ptr(uart_out) });
+}
+
+/// # Safety
+///
+/// `uart_out` must point to a valid `RustByteQueue`.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn rust_da14531_get_connection_state(uart_out: *mut RustByteQueue) {
+ get_connection_state(unsafe { &mut *queue_from_ptr(uart_out) });
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/rust/bitbox02-cbindgen.toml b/src/rust/bitbox02-cbindgen.toml
index 2072e55..cd00777 100644
--- a/src/rust/bitbox02-cbindgen.toml
+++ b/src/rust/bitbox02-cbindgen.toml
@@ -22,10 +22,10 @@ header = '''
parse_deps = true
# ... but only parse these crates.
-include = ["bitbox02", "bitbox02-rust", "util", "bitbox-aes", "bitbox-framed-serial-link", "bitbox-bytequeue"]
+include = ["bitbox02", "bitbox02-rust", "util", "bitbox-aes", "bitbox-da14531", "bitbox-framed-serial-link", "bitbox-bytequeue"]
# also generate bindings from these crates.
-extra_bindings = ["bitbox02", "bitbox02-rust", "util", "bitbox-aes", "bitbox-framed-serial-link", "bitbox-bytequeue"]
+extra_bindings = ["bitbox02", "bitbox02-rust", "util", "bitbox-aes", "bitbox-da14531", "bitbox-framed-serial-link", "bitbox-bytequeue"]
[export]
# malloc, free declared in bitbox02-rust-c/src/c_alloc.rs, but does not need to be exported, as it
diff --git a/src/rust/bitbox02-rust-c/Cargo.toml b/src/rust/bitbox02-rust-c/Cargo.toml
index e1aedad..0bb92ed 100644
--- a/src/rust/bitbox02-rust-c/Cargo.toml
+++ b/src/rust/bitbox02-rust-c/Cargo.toml
@@ -10,6 +10,7 @@ license = "Apache-2.0"
[dependencies]
bitbox02-rust = { path = "../bitbox02-rust", optional = true }
bitbox-bytequeue = { path = "../bitbox-bytequeue" }
+bitbox-da14531 = { path = "../bitbox-da14531" }
bitbox-aes = { path = "../bitbox-aes", optional = true }
bitbox02 = { path = "../bitbox02" }
bitbox-hal = { path = "../bitbox-hal" }
diff --git a/src/rust/bitbox02-rust-c/src/lib.rs b/src/rust/bitbox02-rust-c/src/lib.rs
index af5e796..6b29299 100644
--- a/src/rust/bitbox02-rust-c/src/lib.rs
+++ b/src/rust/bitbox02-rust-c/src/lib.rs
@@ -51,6 +51,8 @@ extern crate bitbox_framed_serial_link;
// Expose C interface defined in bitbox-bytequeue
extern crate bitbox_bytequeue;
+// Expose C interface defined in bitbox-da14531
+extern crate bitbox_da14531;
// Expose C interface defined in util
extern crate util;
diff --git a/test/simulator-graphical-bb03/Cargo.lock b/test/simulator-graphical-bb03/Cargo.lock
index 60fd422..6b30dd2 100644
--- a/test/simulator-graphical-bb03/Cargo.lock
+++ b/test/simulator-graphical-bb03/Cargo.lock
@@ -339,6 +339,7 @@ version = "0.1.0"
dependencies = [
"bitbox-bytequeue",
"bitbox-framed-serial-link",
+ "util",
]
[[package]]
@@ -443,6 +444,7 @@ dependencies = [
"bip39",
"bitbox-aes",
"bitbox-bytequeue",
+ "bitbox-da14531",
"bitbox-framed-serial-link",
"bitbox-hal",
"bitbox02",
diff --git a/test/simulator-graphical/Cargo.lock b/test/simulator-graphical/Cargo.lock
index 47a2b15..51ff865 100644
--- a/test/simulator-graphical/Cargo.lock
+++ b/test/simulator-graphical/Cargo.lock
@@ -301,6 +301,7 @@ version = "0.1.0"
dependencies = [
"bitbox-bytequeue",
"bitbox-framed-serial-link",
+ "util",
]
[[package]]
@@ -405,6 +406,7 @@ dependencies = [
"bip39",
"bitbox-aes",
"bitbox-bytequeue",
+ "bitbox-da14531",
"bitbox-framed-serial-link",
"bitbox-hal",
"bitbox02",
Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.