What changed, and why it matters
This commit rewrites the firmware's USB report queue from C to Rust. It is a large refactoring that replaces a hand-written C ring buffer with a Rust VecDeque wrapped in a C-compatible FFI. The change touches the core USB communication path used by both the main hardware wallet (HWW) and U2F interfaces. There is no explicit security bug fixed or introduced in the diff, but any mistake in the boundary between C and Rust could affect how the device receives and sends USB messages.
Treat this as a high-risk refactoring worth focused review and regression testing. Verify that the new Rust queue preserves the exact concurrency, capacity, and error-handling semantics of the old C queue, especially under interrupt-driven USB traffic. Run the existing U2F/HWW USB protocol tests, fuzz the FFI boundary with null and double-free scenarios, and confirm that all call sites free queues exactly once. Consider adding a static analysis rule to catch mismatched init/free or use-after-free across the C/Rust boundary.
Security signals we found
Large refactoring of security-critical USB I/O path
New C/Rust FFI boundary for queue allocation and access
Manual memory management via Box::into_raw / Box::from_raw
Removal of C critical-section wrappers around queue operations
Capacity preserved but implementation changed from ring buffer to VecDeque
No explicit vulnerability or CVE mentioned in commit message
Evidence from the diff
The patch removes src/queue.c/h and introduces a new no_std Rust crate bitbox-usb-report-queue using alloc::collections::VecDeque to hold 64-byte USB reports. It exposes opaque C FFI functions (init/free/clear/push/pull/peek) and updates usb_processing, usb_frame, usb_packet, u2f_packet, the bootloader, simulators, and unit-test mocks to use RustUsbReportQueue handles instead of the old struct queue. HWW and U2F queues are now allocated separately and passed into their respective init functions. The effective capacity is preserved at USB_DATA_MAX_LEN/USB_REPORT_SIZE - 1 reports. The Rust code includes unit tests for FIFO behavior, overflow, wraparound, null-pointer FFI handling, and init/free.
Changed components
src/rust/bitbox-usb-report-queue/src/lib.rssrc/usb/usb_processing.csrc/usb/usb_frame.csrc/usb/usb_packet.csrc/u2f/u2f_packet.csrc/bootloader/startup.csrc/firmware.csrc/rust/bitbox02-rust/src/main_loop.rstest/simulator/simulator.ctest/unit-test/framework/src/mock_hidapi.cInspect captured patch +653 / −371
diff --git a/AGENTS.md b/AGENTS.md
index d07d4cd..2cf585a 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -7,17 +7,19 @@ Core firmware and bootloader code sits in `src/`, grouped by subsystem (`bootloa
`py/bitbox02`. Supporting tooling is in `scripts/` (CI, J-Link macros), and `doc/` for
manuals. Vendored dependencies are tracked in `external/`.
-The firmware has C and Rust code. Rust code lines in src/rust. The rust crates are:
+The firmware has C and Rust code. Rust code lives in src/rust. The most important rust crates are:
- bitbox02-rust: the main app logic. It can expose functions to C using extern "C". If it needs
- access to C functions, it has to go through the bitbox02 crate. Never add bitbox02-sys dep to
- bitbox02-rust or use if the dep is present.
-- bitbox02-sys: generated bindings to C code. build.rs contains the functions etc that are
- exposed. See also `wrapper.h`, it needs to include any C headers/declarations that are added to
- build.rs.
-- bitbox02: wraps bitbox02-sys functions as idiomatic safe Rust
-
-bitbox02-rust is pure Rust. If it needs to use a C function, it should instead use the safe C
-wrapper in the bitbox02 crate.
+ access to C functions, it has to go through the bitbox-hal crate. Never add bitbox02 or
+ bitbox02-sys dep to bitbox02-rust.
+- bitbox02-sys: generated bindings to bitbox02 specific C code. build.rs contains the functions etc
+ that are exposed. See also `wrapper.h`, it needs to include any C headers/declarations that are
+ added to build.rs.
+- bitbox-hal: provides an interface to device specific functionality
+- bitbox02: wraps bitbox02-sys as idiomatic safe Rust and implements the bitbox-hal interface.
+
+bitbox02-rust is pure Rust and device agnostic. To access device specific functionality it must
+always go through bitbox-hal. The migration is a work in progress, only migrate what is necessary
+for the current scope.
## Build, Test, and Development Commands
- `make dockerpull` / `make dockerdev`: fetch and enter the maintained development container.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 42264cd..16095a2 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -21,7 +21,6 @@ set(DBB-FIRMWARE-SOURCES
${CMAKE_SOURCE_DIR}/src/i2c_ecc.c
${CMAKE_SOURCE_DIR}/src/touch/gestures.c
${CMAKE_SOURCE_DIR}/src/reset.c
- ${CMAKE_SOURCE_DIR}/src/queue.c
${CMAKE_SOURCE_DIR}/src/usb/usb_processing.c
)
set(DBB-FIRMWARE-SOURCES ${DBB-FIRMWARE-SOURCES} PARENT_SCOPE)
@@ -94,7 +93,6 @@ set(DBB-BOOTLOADER-SOURCES
${CMAKE_SOURCE_DIR}/src/memory/nvmctrl.c
${CMAKE_SOURCE_DIR}/src/memory/spi_mem.c
${CMAKE_SOURCE_DIR}/src/memory/memory_spi.c
- ${CMAKE_SOURCE_DIR}/src/queue.c
${CMAKE_SOURCE_DIR}/src/usb/usb_processing.c
${CMAKE_SOURCE_DIR}/src/ui/ugui/ugui.c
${CMAKE_SOURCE_DIR}/src/ui/fonts/font_a_9X9.c
diff --git a/src/bootloader/startup.c b/src/bootloader/startup.c
index 71dbca6..7b306d4 100644
--- a/src/bootloader/startup.c
+++ b/src/bootloader/startup.c
@@ -76,6 +76,7 @@ int main(void)
// If did not jump to firmware code, begin UART/USB processing
const uint8_t* hww_data = NULL;
+ uint8_t hww_data_buf[USB_REPORT_SIZE] = {0};
USB_FRAME hww_frame = {0};
#if PLATFORM_BITBOX02PLUS == 1
@@ -108,7 +109,11 @@ int main(void)
da14531_protocol_init();
#endif
- usb_processing_init();
+ RustUsbReportQueue* hww_queue = rust_usb_report_queue_init();
+ if (hww_queue == NULL) {
+ Abort("Error: malloc hww queue");
+ }
+ usb_processing_init(hww_queue);
while (1) {
// Do UART I/O
@@ -123,7 +128,9 @@ int main(void)
}
#endif
if (!hww_data) {
- hww_data = queue_pull(queue_hww_queue());
+ if (rust_usb_report_queue_pull(hww_queue, hww_data_buf)) {
+ hww_data = hww_data_buf;
+ }
}
if (!hww_data && hid_hww_read((uint8_t*)&hww_frame)) {
usb_packet_process(&hww_frame);
diff --git a/src/firmware.c b/src/firmware.c
index 4ddc6f4..928f6af 100644
--- a/src/firmware.c
+++ b/src/firmware.c
@@ -37,12 +37,6 @@ int main(void)
if (memory_get_platform() == MEMORY_PLATFORM_BITBOX02_PLUS) {
da14531_protocol_init();
}
- usb_processing_init();
- // Setup usb_processing handlers
- hww_setup();
-#if APP_U2F == 1
- u2f_device_setup();
-#endif
rust_main_loop();
return 0;
}
diff --git a/src/queue.c b/src/queue.c
deleted file mode 100644
index 0c03312..0000000
--- a/src/queue.c
+++ /dev/null
@@ -1,152 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-#include "queue.h"
-#include <string.h>
-#include <util.h>
-
-#ifndef TESTING
- #include <hal_atomic.h>
-#else
- #define CRITICAL_SECTION_ENTER()
- #define CRITICAL_SECTION_LEAVE()
-#endif
-
-#include "hardfault.h"
-
-// TODO: get rid of this dependency when USB_DATA_MAX_LEN/USB_REPORT_SIZE is
-// removed.
-#include "usb/usb_frame.h"
-
-// TODO: specify generic size
-// The queue has enough room for a single maximum size packet
-#define QUEUE_NUM_REPORTS (USB_DATA_MAX_LEN / USB_REPORT_SIZE)
-#define QUEUE_SIZE (QUEUE_NUM_REPORTS * USB_REPORT_SIZE)
-
-// `start` and `end` are indices into `items`
-struct queue {
- uint32_t volatile start;
- uint32_t volatile end;
- size_t item_size;
- uint8_t items[QUEUE_SIZE];
-};
-
-/**
- * Thread-unsafe version of queue_clear.
- */
-static void _queue_clear_sync(struct queue* ctx)
-{
- util_zero(ctx->items, sizeof(ctx->items));
- ctx->start = ctx->end = 0;
-}
-
-void queue_clear(struct queue* ctx)
-{
- CRITICAL_SECTION_ENTER();
- _queue_clear_sync(ctx);
- CRITICAL_SECTION_LEAVE();
-}
-
-/**
- * Thread-unsafe version of queue_init.
- */
-static void _queue_init_sync(struct queue* ctx, size_t item_size)
-{
- ctx->item_size = item_size;
- /*
- * The queue only works if the size of each item is a submultiple of
- * QUEUE_SIZE.
- */
- if (QUEUE_SIZE % item_size != 0) {
- Abort("Queue initialized with wrong item size.");
- }
- queue_clear(ctx);
-}
-
-void queue_init(struct queue* ctx, size_t item_size)
-{
- CRITICAL_SECTION_ENTER();
- _queue_init_sync(ctx, item_size);
- CRITICAL_SECTION_LEAVE();
-}
-
-/**
- * Thread-unsafe version of queue_pull.
- */
-static const uint8_t* _queue_pull_sync(struct queue* ctx)
-{
- uint32_t p = ctx->start;
- if (p == ctx->end) {
- // queue is empty
- return NULL;
- }
- ctx->start = (p + ctx->item_size) % QUEUE_SIZE;
- return ctx->items + p;
-}
-
-const uint8_t* queue_pull(struct queue* ctx)
-{
- const uint8_t* result;
- CRITICAL_SECTION_ENTER();
- result = _queue_pull_sync(ctx);
- CRITICAL_SECTION_LEAVE();
- return result;
-}
-
-/**
- * Thread-unsafe version of queue_push.
- */
-static queue_error_t _queue_push_sync(struct queue* ctx, const uint8_t* data)
-{
- uint32_t next = (ctx->end + ctx->item_size) % QUEUE_SIZE;
- if (ctx->start == next) {
- return QUEUE_ERR_FULL; // Buffer full
- }
- memcpy(ctx->items + ctx->end, data, ctx->item_size);
- ctx->end = next;
- return QUEUE_ERR_NONE;
-}
-
-queue_error_t queue_push(struct queue* ctx, const uint8_t* data)
-{
- queue_error_t result;
- CRITICAL_SECTION_ENTER();
- result = _queue_push_sync(ctx, data);
- CRITICAL_SECTION_LEAVE();
- return result;
-}
-
-/**
- * Thread-unsafe version of queue_peek.
- */
-static const uint8_t* _queue_peek_sync(struct queue* ctx)
-{
- uint32_t p = ctx->start;
- if (p == ctx->end) {
- // queue is empty
- return NULL;
- }
- return ctx->items + p;
-}
-
-const uint8_t* queue_peek(struct queue* ctx)
-{
- const uint8_t* result;
- CRITICAL_SECTION_ENTER();
- result = _queue_peek_sync(ctx);
- CRITICAL_SECTION_LEAVE();
- return result;
-}
-
-struct queue* queue_hww_queue(void)
-{
- static struct queue queue;
- return &queue;
-}
-
-#if APP_U2F == 1
-struct queue* queue_u2f_queue(void)
-{
- static struct queue queue;
- return &queue;
-}
-#endif
diff --git a/src/queue.h b/src/queue.h
deleted file mode 100644
index e0d6abc..0000000
--- a/src/queue.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-#ifndef _QUEUE_H
-#define _QUEUE_H
-
-#include <stdint.h>
-#include <string.h>
-
-typedef enum {
- QUEUE_ERR_NONE = 0,
- QUEUE_ERR_FULL = 1,
-} queue_error_t;
-
-struct queue;
-
-/**
- * Append the given data to the queue.
- * Returns QUEUE_ERR_NONE if the data was added and QUEUE_ERR_FULL if the buffer was full.
- * data must be USB_REPORT_SIZE large
- */
-queue_error_t queue_push(struct queue* ctx, const uint8_t* data);
-
-/**
- * Return the first data that was added to the queue.
- * Returns NULL if empty
- */
-const uint8_t* queue_pull(struct queue* ctx);
-
-/**
- * Initializes this queue object.
- * The queue will handle elements with the given size.
- *
- * @param[size] Size of each element. This will decide how many
- * bytes each push/pull operation will consume. This must be
- * a submultiple of QUEUE_SIZE.
- */
-void queue_init(struct queue* ctx, size_t item_size);
-
-/**
- * Clear the queue.
- */
-void queue_clear(struct queue* ctx);
-
-/**
- * Peek at the tip of the queue. Returns NULL if queue is empty.
- */
-const uint8_t* queue_peek(struct queue* ctx);
-
-/**
- * Get a pointer to the hww queue
- */
-struct queue* queue_hww_queue(void);
-
-/**
- * Get a pointer ot the u2f queue
- */
-struct queue* queue_u2f_queue(void);
-
-#endif
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
index 589cfb6..4a47aa6 100644
--- a/src/rust/Cargo.lock
+++ b/src/rust/Cargo.lock
@@ -174,6 +174,13 @@ dependencies = [
"hex_lit",
]
+[[package]]
+name = "bitbox-usb-report-queue"
+version = "0.1.0"
+dependencies = [
+ "cortex-m",
+]
+
[[package]]
name = "bitbox02"
version = "0.1.0"
@@ -183,6 +190,7 @@ dependencies = [
"bitbox-bytequeue",
"bitbox-framed-serial-link",
"bitbox-hal",
+ "bitbox-usb-report-queue",
"bitbox02-noise",
"bitbox02-sys",
"futures-lite",
@@ -214,6 +222,7 @@ dependencies = [
"bitbox-executor",
"bitbox-hal",
"bitbox-secp256k1",
+ "bitbox-usb-report-queue",
"bitbox02",
"bitbox02-noise",
"bitcoin",
@@ -252,6 +261,7 @@ dependencies = [
"bitbox-da14531",
"bitbox-framed-serial-link",
"bitbox-hal",
+ "bitbox-usb-report-queue",
"bitbox02",
"bitbox02-noise",
"bitbox02-rust",
diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml
index c10421a..790f28b 100644
--- a/src/rust/Cargo.toml
+++ b/src/rust/Cargo.toml
@@ -5,6 +5,7 @@
members = [
"bitbox02-rust-c",
"bitbox02-rust",
+ "bitbox-usb-report-queue",
"bitbox-bytequeue",
"bitbox-da14531",
"bitbox-hal",
diff --git a/src/rust/bitbox-usb-report-queue/Cargo.toml b/src/rust/bitbox-usb-report-queue/Cargo.toml
new file mode 100644
index 0000000..6324fe9
--- /dev/null
+++ b/src/rust/bitbox-usb-report-queue/Cargo.toml
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: Apache-2.0
+
+[package]
+name = "bitbox-usb-report-queue"
+version = "0.1.0"
+authors = ["Shift Crypto AG <support@bitbox.swiss>"]
+edition = "2024"
+license = "Apache-2.0"
+
+[dependencies]
+
+[target.'cfg(target_arch = "arm")'.dependencies]
+cortex-m = { workspace = true }
diff --git a/src/rust/bitbox-usb-report-queue/src/lib.rs b/src/rust/bitbox-usb-report-queue/src/lib.rs
new file mode 100644
index 0000000..1dd95d7
--- /dev/null
+++ b/src/rust/bitbox-usb-report-queue/src/lib.rs
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#![no_std]
+
+extern crate alloc;
+
+use alloc::boxed::Box;
+use alloc::collections::VecDeque;
+
+const USB_REPORT_SIZE: usize = 64;
+// Keep this in sync with USB_DATA_MAX_LEN in src/usb/usb_frame.h.
+const USB_DATA_MAX_LEN: usize = 7609;
+const USB_REPORT_QUEUE_NUM_REPORTS: usize = USB_DATA_MAX_LEN / USB_REPORT_SIZE;
+// Preserve the previous effective capacity of the manual ring buffer, which
+// kept one slot empty to distinguish full from empty.
+const USB_REPORT_QUEUE_MAX_LEN: usize = USB_REPORT_QUEUE_NUM_REPORTS - 1;
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[repr(u8)]
+#[allow(non_camel_case_types)]
+pub enum UsbReportQueueError {
+ USB_REPORT_QUEUE_ERR_NONE = 0,
+ USB_REPORT_QUEUE_ERR_FULL = 1,
+}
+
+type UsbReport = [u8; USB_REPORT_SIZE];
+
+pub struct UsbReportQueue {
+ reports: VecDeque<UsbReport>,
+}
+
+#[repr(C)]
+pub struct RustUsbReportQueue {
+ _private: [u8; 0],
+}
+
+impl UsbReportQueue {
+ pub const fn new() -> Self {
+ Self {
+ reports: VecDeque::new(),
+ }
+ }
+
+ pub fn as_mut_ptr(&mut self) -> *mut RustUsbReportQueue {
+ (self as *mut Self).cast::<RustUsbReportQueue>()
+ }
+
+ pub fn clear(&mut self) {
+ self.reports.clear();
+ }
+
+ pub fn push(&mut self, report: &[u8; USB_REPORT_SIZE]) -> UsbReportQueueError {
+ if self.reports.len() >= USB_REPORT_QUEUE_MAX_LEN {
+ return UsbReportQueueError::USB_REPORT_QUEUE_ERR_FULL;
+ }
+ self.reports.push_back(*report);
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_NONE
+ }
+
+ pub fn pull(&mut self) -> Option<[u8; USB_REPORT_SIZE]> {
+ self.reports.pop_front()
+ }
+
+ pub fn peek(&self) -> Option<[u8; USB_REPORT_SIZE]> {
+ self.reports.front().copied()
+ }
+}
+
+impl Default for UsbReportQueue {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+unsafe fn queue_mut<'a>(queue: *mut RustUsbReportQueue) -> Option<&'a mut UsbReportQueue> {
+ if queue.is_null() {
+ return None;
+ }
+ Some(unsafe { &mut *queue.cast::<UsbReportQueue>() })
+}
+
+unsafe fn queue_ref<'a>(queue: *const RustUsbReportQueue) -> Option<&'a UsbReportQueue> {
+ if queue.is_null() {
+ return None;
+ }
+ Some(unsafe { &*queue.cast::<UsbReportQueue>() })
+}
+
+/// Allocates a new USB report queue and returns an opaque handle.
+///
+/// The returned pointer must be freed with [`rust_usb_report_queue_free`].
+#[unsafe(no_mangle)]
+pub extern "C" fn rust_usb_report_queue_init() -> *mut RustUsbReportQueue {
+ Box::into_raw(Box::new(UsbReportQueue::new())).cast::<RustUsbReportQueue>()
+}
+
+/// Frees a USB report queue previously created by [`rust_usb_report_queue_init`].
+///
+/// # Safety
+/// If `queue` is non-null, it must be a pointer returned by
+/// [`rust_usb_report_queue_init`] that has not already been freed.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn rust_usb_report_queue_free(queue: *mut RustUsbReportQueue) -> bool {
+ if queue.is_null() {
+ return false;
+ }
+
+ unsafe { drop(Box::from_raw(queue.cast::<UsbReportQueue>())) };
+ true
+}
+
+/// Clears the given USB report queue.
+///
+/// # Safety
+/// `queue` must be null or a valid queue returned by
+/// [`rust_usb_report_queue_init`] or [`UsbReportQueue::as_mut_ptr`].
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn rust_usb_report_queue_clear(queue: *mut RustUsbReportQueue) {
+ if let Some(queue) = unsafe { queue_mut(queue) } {
+ queue.clear();
+ }
+}
+
+/// Pushes one 64-byte USB report to the queue.
+///
+/// # Safety
+/// `queue` must be null or a valid queue returned by
+/// [`rust_usb_report_queue_init`] or [`UsbReportQueue::as_mut_ptr`].
+///
+/// `report` must point to 64 readable bytes.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn rust_usb_report_queue_push(
+ queue: *mut RustUsbReportQueue,
+ report: *const u8,
+) -> UsbReportQueueError {
+ if report.is_null() {
+ return UsbReportQueueError::USB_REPORT_QUEUE_ERR_FULL;
+ }
+ let report = unsafe { &*report.cast::<UsbReport>() };
+ unsafe { queue_mut(queue) }
+ .map(|queue| queue.push(report))
+ .unwrap_or(UsbReportQueueError::USB_REPORT_QUEUE_ERR_FULL)
+}
+
+/// Pulls one 64-byte USB report from the queue into `report_out`.
+///
+/// # Safety
+/// `queue` must be null or a valid queue returned by
+/// [`rust_usb_report_queue_init`] or [`UsbReportQueue::as_mut_ptr`].
+///
+/// `report_out` must point to 64 writable bytes.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn rust_usb_report_queue_pull(
+ queue: *mut RustUsbReportQueue,
+ report_out: *mut u8,
+) -> bool {
+ if report_out.is_null() {
+ return false;
+ }
+ let Some(report) = unsafe { queue_mut(queue) }.and_then(UsbReportQueue::pull) else {
+ return false;
+ };
+ unsafe { *report_out.cast::<UsbReport>() = report };
+ true
+}
+
+/// Copies the next 64-byte USB report into `report_out` without consuming it.
+///
+/// # Safety
+/// `queue` must be null or a valid queue returned by
+/// [`rust_usb_report_queue_init`] or [`UsbReportQueue::as_mut_ptr`].
+///
+/// `report_out` must point to 64 writable bytes.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn rust_usb_report_queue_peek(
+ queue: *const RustUsbReportQueue,
+ report_out: *mut u8,
+) -> bool {
+ if report_out.is_null() {
+ return false;
+ }
+ let Some(report) = unsafe { queue_ref(queue) }.and_then(UsbReportQueue::peek) else {
+ return false;
+ };
+ unsafe { *report_out.cast::<UsbReport>() = report };
+ true
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use core::ptr;
+
+ fn report(fill: u8) -> UsbReport {
+ [fill; USB_REPORT_SIZE]
+ }
+
+ #[test]
+ fn test_push_pull_fifo() {
+ let mut queue = UsbReportQueue::new();
+
+ assert!(matches!(
+ queue.push(&report(1)),
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_NONE
+ ));
+ assert!(matches!(
+ queue.push(&report(2)),
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_NONE
+ ));
+ assert_eq!(queue.pull().unwrap(), report(1));
+ assert_eq!(queue.pull().unwrap(), report(2));
+ assert!(queue.pull().is_none());
+ }
+
+ #[test]
+ fn test_pull_empty() {
+ let mut queue = UsbReportQueue::new();
+ assert!(queue.pull().is_none());
+ }
+
+ #[test]
+ fn test_peek_does_not_consume() {
+ let mut queue = UsbReportQueue::new();
+ assert!(matches!(
+ queue.push(&report(3)),
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_NONE
+ ));
+ assert_eq!(queue.peek().unwrap(), report(3));
+ assert_eq!(queue.pull().unwrap(), report(3));
+ }
+
+ #[test]
+ fn test_clear_empties_queue() {
+ let mut queue = UsbReportQueue::new();
+ assert!(matches!(
+ queue.push(&report(4)),
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_NONE
+ ));
+ queue.clear();
+ assert!(queue.pull().is_none());
+ }
+
+ #[test]
+ fn test_overflow_returns_full() {
+ let mut queue = UsbReportQueue::new();
+
+ for i in 0..USB_REPORT_QUEUE_MAX_LEN {
+ assert!(matches!(
+ queue.push(&report((i % 251) as u8)),
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_NONE
+ ));
+ }
+
+ assert!(matches!(
+ queue.push(&report(0xff)),
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_FULL
+ ));
+ }
+
+ #[test]
+ fn test_wraparound_fifo_order() {
+ let mut queue = UsbReportQueue::new();
+
+ for i in 0..USB_REPORT_QUEUE_MAX_LEN {
+ assert!(matches!(
+ queue.push(&report((i % 251) as u8)),
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_NONE
+ ));
+ }
+
+ for i in 0..16 {
+ assert_eq!(queue.pull().unwrap(), report((i % 251) as u8));
+ }
+
+ for i in 0..16 {
+ assert!(matches!(
+ queue.push(&report((200 + i) as u8)),
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_NONE
+ ));
+ }
+
+ for i in 16..USB_REPORT_QUEUE_MAX_LEN {
+ assert_eq!(queue.pull().unwrap(), report((i % 251) as u8));
+ }
+
+ for i in 0..16 {
+ assert_eq!(queue.pull().unwrap(), report((200 + i) as u8));
+ }
+ }
+
+ #[test]
+ fn test_null_ffi_arguments() {
+ let mut out = [0u8; USB_REPORT_SIZE];
+ let mut queue = UsbReportQueue::new();
+ let queue = queue.as_mut_ptr();
+ assert!(matches!(
+ unsafe { rust_usb_report_queue_push(ptr::null_mut(), report(7).as_ptr()) },
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_FULL
+ ));
+ assert!(matches!(
+ unsafe { rust_usb_report_queue_push(queue, ptr::null()) },
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_FULL
+ ));
+ unsafe {
+ rust_usb_report_queue_clear(ptr::null_mut());
+ }
+ assert!(!unsafe { rust_usb_report_queue_pull(ptr::null_mut(), out.as_mut_ptr()) });
+ assert!(!unsafe { rust_usb_report_queue_pull(queue, ptr::null_mut()) });
+ assert!(!unsafe { rust_usb_report_queue_peek(ptr::null(), out.as_mut_ptr()) });
+ assert!(!unsafe { rust_usb_report_queue_peek(queue, ptr::null_mut()) });
+ }
+
+ #[test]
+ fn test_hww_and_u2f_are_independent() {
+ let mut hww_queue = UsbReportQueue::new();
+ let mut u2f_queue = UsbReportQueue::new();
+ let hww = hww_queue.as_mut_ptr();
+ let u2f = u2f_queue.as_mut_ptr();
+ let mut out = [0u8; USB_REPORT_SIZE];
+
+ unsafe {
+ assert!(matches!(
+ rust_usb_report_queue_push(hww, report(0x11).as_ptr()),
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_NONE
+ ));
+ assert!(matches!(
+ rust_usb_report_queue_push(u2f, report(0x22).as_ptr()),
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_NONE
+ ));
+
+ assert!(rust_usb_report_queue_pull(hww, out.as_mut_ptr()));
+ assert_eq!(out, report(0x11));
+
+ assert!(rust_usb_report_queue_pull(u2f, out.as_mut_ptr()));
+ assert_eq!(out, report(0x22));
+ }
+ }
+
+ #[test]
+ fn test_ffi_pull_and_peek() {
+ let mut queue = UsbReportQueue::new();
+ let queue = queue.as_mut_ptr();
+ let pushed = report(9);
+ let mut out = [0u8; USB_REPORT_SIZE];
+
+ assert!(matches!(
+ unsafe { rust_usb_report_queue_push(queue, pushed.as_ptr()) },
+ UsbReportQueueError::USB_REPORT_QUEUE_ERR_NONE
+ ));
+ assert!(unsafe { rust_usb_report_queue_peek(queue, out.as_mut_ptr()) });
+ assert_eq!(out, pushed);
+ out = [0; USB_REPORT_SIZE];
+ assert!(unsafe { rust_usb_report_queue_pull(queue, out.as_mut_ptr()) });
+ assert_eq!(out, pushed);
+ assert!(!unsafe { rust_usb_report_queue_pull(queue, out.as_mut_ptr()) });
+ }
+
+ #[test]
+ fn test_rust_usb_report_queue_init_free() {
+ let queue = rust_usb_report_queue_init();
+ assert!(!queue.is_null());
+ assert!(unsafe { rust_usb_report_queue_free(queue) });
+ assert!(!unsafe { rust_usb_report_queue_free(ptr::null_mut()) });
+ }
+}
diff --git a/src/rust/bitbox02-cbindgen.toml b/src/rust/bitbox02-cbindgen.toml
index cd00777..918e708 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-da14531", "bitbox-framed-serial-link", "bitbox-bytequeue"]
+include = ["bitbox02", "bitbox02-rust", "util", "bitbox-aes", "bitbox-da14531", "bitbox-framed-serial-link", "bitbox-bytequeue", "bitbox-usb-report-queue"]
# also generate bindings from these crates.
-extra_bindings = ["bitbox02", "bitbox02-rust", "util", "bitbox-aes", "bitbox-da14531", "bitbox-framed-serial-link", "bitbox-bytequeue"]
+extra_bindings = ["bitbox02", "bitbox02-rust", "util", "bitbox-aes", "bitbox-da14531", "bitbox-framed-serial-link", "bitbox-bytequeue", "bitbox-usb-report-queue"]
[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 0bb92ed..677eb19 100644
--- a/src/rust/bitbox02-rust-c/Cargo.toml
+++ b/src/rust/bitbox02-rust-c/Cargo.toml
@@ -9,6 +9,7 @@ license = "Apache-2.0"
[dependencies]
bitbox02-rust = { path = "../bitbox02-rust", optional = true }
+bitbox-usb-report-queue = { path = "../bitbox-usb-report-queue" }
bitbox-bytequeue = { path = "../bitbox-bytequeue" }
bitbox-da14531 = { path = "../bitbox-da14531" }
bitbox-aes = { path = "../bitbox-aes", optional = true }
diff --git a/src/rust/bitbox02-rust-c/src/lib.rs b/src/rust/bitbox02-rust-c/src/lib.rs
index 6b29299..3525176 100644
--- a/src/rust/bitbox02-rust-c/src/lib.rs
+++ b/src/rust/bitbox02-rust-c/src/lib.rs
@@ -54,6 +54,9 @@ extern crate bitbox_bytequeue;
// Expose C interface defined in bitbox-da14531
extern crate bitbox_da14531;
+// Expose C interface defined in bitbox-usb-report-queue
+extern crate bitbox_usb_report_queue;
+
// Expose C interface defined in util
extern crate util;
diff --git a/src/rust/bitbox02-rust/Cargo.toml b/src/rust/bitbox02-rust/Cargo.toml
index e26bf40..4a727d4 100644
--- a/src/rust/bitbox02-rust/Cargo.toml
+++ b/src/rust/bitbox02-rust/Cargo.toml
@@ -18,6 +18,7 @@ bitbox-hal = { path = "../bitbox-hal" }
bitbox-da14531 = { path = "../bitbox-da14531" }
bitbox02 = { path = "../bitbox02" }
bitbox-bytequeue = { path = "../bitbox-bytequeue" }
+bitbox-usb-report-queue = { path = "../bitbox-usb-report-queue" }
bitbox-secp256k1 = { path = "../bitbox-secp256k1" }
util = { path = "../util" }
erc20_params = { path = "../erc20_params", optional = true }
diff --git a/src/rust/bitbox02-rust/src/main_loop.rs b/src/rust/bitbox02-rust/src/main_loop.rs
index 85c1331..c2d7ff1 100644
--- a/src/rust/bitbox02-rust/src/main_loop.rs
+++ b/src/rust/bitbox02-rust/src/main_loop.rs
@@ -4,6 +4,7 @@ use crate::hal::{Memory, System};
use alloc::boxed::Box;
use bitbox_bytequeue::ByteQueue;
use bitbox_executor::Executor;
+use bitbox_usb_report_queue::UsbReportQueue;
use bitbox02::uart::USART_0_BUFFER_SIZE;
use bitbox02::usb_packet::USB_FRAME;
use core::future::Future;
@@ -27,6 +28,16 @@ pub fn main_loop<H: crate::hal::Hal>(hal: &mut H) -> ! {
let mut uart_read_buf_len = 0u16;
let mut uart_write_queue = ByteQueue::with_capacity(2048);
+ let mut hww_queue = UsbReportQueue::new();
+ #[cfg(feature = "app-u2f")]
+ let mut u2f_queue = UsbReportQueue::new();
+
+ bitbox02::usb_processing::init(&mut hww_queue);
+ #[cfg(feature = "app-u2f")]
+ bitbox02::usb_processing::init_u2f(&mut u2f_queue);
+ bitbox02::hww::setup();
+ #[cfg(feature = "app-u2f")]
+ bitbox02::u2f::setup();
// If the bootloader has booted the BLE chip, the BLE chip isn't aware of the name according to
// the fw. Send it over.
@@ -41,7 +52,6 @@ pub fn main_loop<H: crate::hal::Hal>(hal: &mut H) -> ! {
let mut hww_data = None;
let mut hww_frame: USB_FRAME = unsafe { MaybeUninit::zeroed().assume_init() };
-
#[cfg(feature = "app-u2f")]
bitbox02::u2f_packet::init();
#[cfg(feature = "app-u2f")]
@@ -67,7 +77,7 @@ pub fn main_loop<H: crate::hal::Hal>(hal: &mut H) -> ! {
// Check if there is outgoing data
if hww_data.is_none() {
- hww_data = bitbox02::queue::pull_hww();
+ hww_data = hww_queue.pull();
}
// Generate u2f timeout packets
@@ -79,7 +89,7 @@ pub fn main_loop<H: crate::hal::Hal>(hal: &mut H) -> ! {
bitbox02::u2f_packet::timeout(timeout_cid);
}
if u2f_data.is_none() {
- u2f_data = bitbox02::queue::pull_u2f();
+ u2f_data = u2f_queue.pull();
// If USB stack was locked and there is no more messages to send out, time to
// unlock it.
if u2f_data.is_none() && bitbox02::usb_processing::locked_u2f() {
diff --git a/src/rust/bitbox02-sys/build.rs b/src/rust/bitbox02-sys/build.rs
index db89baf..619d1a4 100644
--- a/src/rust/bitbox02-sys/build.rs
+++ b/src/rust/bitbox02-sys/build.rs
@@ -42,13 +42,19 @@ const ALLOWLIST_TYPES: &[&str] = &[
"delay_t",
"event_slider_data_t",
"event_types",
+ "RustByteQueue",
+ "RustUsbReportQueue",
"securechip_error_t",
"trinary_input_string_params_t",
"UG_COLOR",
"upside_down_t",
];
-const OPAQUE_TYPES: &[&str] = &["da14531_protocol_frame"];
+const OPAQUE_TYPES: &[&str] = &[
+ "da14531_protocol_frame",
+ "RustByteQueue",
+ "RustUsbReportQueue",
+];
const ALLOWLIST_FNS: &[&str] = &[
"bip32_derive_xpub",
@@ -124,9 +130,6 @@ const ALLOWLIST_FNS: &[&str] = &[
"printf",
"progress_create",
"progress_set",
- "queue_hww_queue",
- "queue_pull",
- "queue_u2f_queue",
"random_32_bytes_mcu",
"random_32_bytes",
"random_fake_reset",
@@ -172,6 +175,7 @@ const ALLOWLIST_FNS: &[&str] = &[
"u2f_packet_process",
"u2f_packet_timeout_get",
"u2f_packet_timeout",
+ "u2f_device_setup",
"u2f_process",
"uart_poll",
"UG_ClearBuffer",
@@ -185,6 +189,7 @@ const ALLOWLIST_FNS: &[&str] = &[
"usb_packet_process",
"usb_processing_hww",
"usb_processing_init",
+ "usb_processing_init_u2f",
"usb_processing_locked",
"usb_processing_process",
"usb_processing_timeout_reset",
@@ -222,7 +227,6 @@ const BITBOX02_SOURCES: &[&str] = &[
"src/memory/memory_spi.c",
"src/memory/memory.c",
"src/platform/platform_init.c",
- "src/queue.c",
"src/random.c",
"src/reset.c",
"src/screen.c",
diff --git a/src/rust/bitbox02/Cargo.toml b/src/rust/bitbox02/Cargo.toml
index 2a4a541..af54fc7 100644
--- a/src/rust/bitbox02/Cargo.toml
+++ b/src/rust/bitbox02/Cargo.toml
@@ -14,6 +14,7 @@ bitbox02-noise = { path = "../bitbox02-noise" }
bitbox-hal = { path = "../bitbox-hal" }
bitbox-bytequeue = { path = "../bitbox-bytequeue" }
bitbox-framed-serial-link = { path = "../bitbox-framed-serial-link" }
+bitbox-usb-report-queue = { path = "../bitbox-usb-report-queue" }
util = {path = "../util"}
zeroize = { workspace = true }
bip39 = { workspace = true }
diff --git a/src/rust/bitbox02/src/lib.rs b/src/rust/bitbox02/src/lib.rs
index 9901e19..2ac61a8 100644
--- a/src/rust/bitbox02/src/lib.rs
+++ b/src/rust/bitbox02/src/lib.rs
@@ -28,11 +28,9 @@ pub mod hal;
pub mod hid_hww;
#[cfg(feature = "app-u2f")]
pub mod hid_u2f;
-#[cfg(feature = "simulator-graphical")]
pub mod hww;
pub mod memory;
pub mod platform;
-pub mod queue;
pub mod random;
pub mod screen;
pub mod screen_saver;
diff --git a/src/rust/bitbox02/src/queue.rs b/src/rust/bitbox02/src/queue.rs
deleted file mode 100644
index d7657f8..0000000
--- a/src/rust/bitbox02/src/queue.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-pub fn pull_hww() -> Option<[u8; 64]> {
- let hww_data = unsafe { bitbox02_sys::queue_pull(bitbox02_sys::queue_hww_queue()) };
- if hww_data.is_null() {
- return None;
- }
- let mut data: [u8; 64] = [0; 64];
- unsafe { core::ptr::copy_nonoverlapping(hww_data, data.as_mut_ptr(), 64) }
- Some(data)
-}
-
-#[cfg(feature = "app-u2f")]
-pub fn pull_u2f() -> Option<[u8; 64]> {
- let u2f_data = unsafe { bitbox02_sys::queue_pull(bitbox02_sys::queue_u2f_queue()) };
- if u2f_data.is_null() {
- return None;
- }
- let mut data: [u8; 64] = [0; 64];
- unsafe { core::ptr::copy_nonoverlapping(u2f_data, data.as_mut_ptr(), 64) }
- Some(data)
-}
diff --git a/src/rust/bitbox02/src/u2f.rs b/src/rust/bitbox02/src/u2f.rs
index b3d02ba..4681df9 100644
--- a/src/rust/bitbox02/src/u2f.rs
+++ b/src/rust/bitbox02/src/u2f.rs
@@ -1,5 +1,11 @@
// SPDX-License-Identifier: Apache-2.0
+pub fn setup() {
+ unsafe {
+ bitbox02_sys::u2f_device_setup();
+ }
+}
+
pub fn process() {
unsafe {
bitbox02_sys::u2f_process();
diff --git a/src/rust/bitbox02/src/usb_processing.rs b/src/rust/bitbox02/src/usb_processing.rs
index a199115..30447ae 100644
--- a/src/rust/bitbox02/src/usb_processing.rs
+++ b/src/rust/bitbox02/src/usb_processing.rs
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
+use bitbox_usb_report_queue::UsbReportQueue;
+
/// Reset the USB processing timeout to the given value.
pub fn timeout_reset(value: i16) {
unsafe {
@@ -7,9 +9,25 @@ pub fn timeout_reset(value: i16) {
}
}
-#[cfg(feature = "simulator-graphical")]
-pub fn init() {
- unsafe { bitbox02_sys::usb_processing_init() }
+pub fn init(hww_queue: &mut UsbReportQueue) {
+ unsafe {
+ bitbox02_sys::usb_processing_init(
+ hww_queue
+ .as_mut_ptr()
+ .cast::<bitbox02_sys::RustUsbReportQueue>(),
+ )
+ }
+}
+
+#[cfg(feature = "app-u2f")]
+pub fn init_u2f(u2f_queue: &mut UsbReportQueue) {
+ unsafe {
+ bitbox02_sys::usb_processing_init_u2f(
+ u2f_queue
+ .as_mut_ptr()
+ .cast::<bitbox02_sys::RustUsbReportQueue>(),
+ )
+ }
}
pub fn process_hww() {
diff --git a/src/u2f/u2f_packet.c b/src/u2f/u2f_packet.c
index 5415ada..5f0d33a 100644
--- a/src/u2f/u2f_packet.c
+++ b/src/u2f/u2f_packet.c
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
#include "u2f_packet.h"
-#include "queue.h"
#include "screen.h"
#include "usb/usb_processing.h"
+#include <rust/rust.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -46,12 +46,17 @@ static void _timeout_disable(uint32_t cid)
*/
static State _in_state;
+static RustUsbReportQueue* _out_queue(void)
+{
+ return usb_processing_out_queue(usb_processing_u2f());
+}
+
/**
* Resets the current state.
*/
static void _reset_state(void)
{
- queue_clear(queue_u2f_queue());
+ rust_usb_report_queue_clear(_out_queue());
_timeout_disable(_in_state.cid);
memset(&_in_state, 0, sizeof(_in_state));
_in_state.buf_ptr = _in_state.data;
@@ -65,7 +70,7 @@ static void _reset_state(void)
*/
static void _queue_err(const uint8_t err, uint32_t cid)
{
- usb_frame_prepare_err(err, cid, queue_u2f_queue());
+ usb_frame_prepare_err(err, cid, _out_queue());
}
static bool _need_more_data(void)
@@ -73,7 +78,7 @@ static bool _need_more_data(void)
return (_in_state.buf_ptr - _in_state.data) < (signed)_in_state.len;
}
-void u2f_invalid_endpoint(struct queue* queue, uint32_t cid)
+void u2f_invalid_endpoint(RustUsbReportQueue* queue, uint32_t cid)
{
// TODO: if U2F is disabled, we used to return a 'channel busy' command.
// now we return an invalid cmd, because there is not going to be a matching
@@ -120,7 +125,7 @@ void u2f_packet_timeout(uint32_t cid)
if (cid == _in_state.cid) {
_reset_state();
}
- usb_frame_prepare_err(FRAME_ERR_MSG_TIMEOUT, cid, queue_u2f_queue());
+ usb_frame_prepare_err(FRAME_ERR_MSG_TIMEOUT, cid, _out_queue());
}
bool u2f_packet_process(const USB_FRAME* frame)
diff --git a/src/u2f/u2f_packet.h b/src/u2f/u2f_packet.h
index 7f39de3..df5495c 100644
--- a/src/u2f/u2f_packet.h
+++ b/src/u2f/u2f_packet.h
@@ -40,7 +40,7 @@ void u2f_packet_timeout_enable(uint32_t cid);
* Called when a message has been received, but there is no
* API registered to handle the requested U2F Command (endpoint) byte.
*/
-void u2f_invalid_endpoint(struct queue* queue, uint32_t cid);
+void u2f_invalid_endpoint(RustUsbReportQueue* queue, uint32_t cid);
void u2f_packet_init(void);
diff --git a/src/usb/class/hid/hww/hid_hww.c b/src/usb/class/hid/hww/hid_hww.c
index 0499138..f1c5ca7 100644
--- a/src/usb/class/hid/hww/hid_hww.c
+++ b/src/usb/class/hid/hww/hid_hww.c
@@ -3,7 +3,6 @@
#include "hid_hww.h"
#include "usb/usb_processing.h"
#include "usb_desc.h"
-#include <queue.h>
#include <string.h>
#include <usb/usb_packet.h>
diff --git a/src/usb/class/hid/u2f/hid_u2f.c b/src/usb/class/hid/u2f/hid_u2f.c
index 6780bbd..726544c 100644
--- a/src/usb/class/hid/u2f/hid_u2f.c
+++ b/src/usb/class/hid/u2f/hid_u2f.c
@@ -4,7 +4,6 @@
#include "usb/usb_processing.h"
#include "usb_size.h"
#include "usb_u2f_desc.h"
-#include <queue.h>
#include <string.h>
#include <u2f/u2f_packet.h>
diff --git a/src/usb/usb_frame.c b/src/usb/usb_frame.c
index 9896cd5..08aa96b 100644
--- a/src/usb/usb_frame.c
+++ b/src/usb/usb_frame.c
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
#include "usb_frame.h"
-#include "queue.h"
#if APP_U2F == 1
#include "u2f/u2f_packet.h"
#endif
@@ -110,12 +109,12 @@ static int32_t _cmd_continue(const USB_FRAME* frame, State* state)
* Prepares USB frames to be send to the host.
* param[in] data The data is copied into one or more frames
*/
-queue_error_t usb_frame_reply(
+UsbReportQueueError usb_frame_reply(
uint8_t cmd,
const uint8_t* data,
uint32_t len,
uint32_t cid,
- struct queue* queue)
+ RustUsbReportQueue* queue)
{
USB_FRAME frame;
uint32_t cnt = 0;
@@ -132,8 +131,8 @@ queue_error_t usb_frame_reply(
// Init frame
psz = MIN(sizeof(frame.init.data), l);
memcpy(frame.init.data, data, psz);
- queue_error_t err = queue_push(queue, (const uint8_t*)&frame);
- if (err != QUEUE_ERR_NONE) {
+ UsbReportQueueError err = rust_usb_report_queue_push(queue, (const uint8_t*)&frame);
+ if (err != USB_REPORT_QUEUE_ERR_NONE) {
return err;
}
l -= psz;
@@ -145,12 +144,12 @@ queue_error_t usb_frame_reply(
frame.cont.seq = seq++;
psz = MIN(sizeof(frame.cont.data), l);
memcpy(frame.cont.data, data + cnt, psz);
- err = queue_push(queue, (const uint8_t*)&frame);
- if (err != QUEUE_ERR_NONE) {
+ err = rust_usb_report_queue_push(queue, (const uint8_t*)&frame);
+ if (err != USB_REPORT_QUEUE_ERR_NONE) {
return err;
}
}
- return QUEUE_ERR_NONE;
+ return USB_REPORT_QUEUE_ERR_NONE;
}
/**
@@ -160,7 +159,7 @@ queue_error_t usb_frame_reply(
* @param[in] cid The channel id.
* @param[in] add_frame_callback The callback to which we add the frame.
*/
-queue_error_t usb_frame_prepare_err(uint8_t err, uint32_t cid, struct queue* queue)
+UsbReportQueueError usb_frame_prepare_err(uint8_t err, uint32_t cid, RustUsbReportQueue* queue)
{
USB_FRAME frame;
@@ -169,7 +168,7 @@ queue_error_t usb_frame_prepare_err(uint8_t err, uint32_t cid, struct queue* que
frame.init.cmd = FRAME_ERROR;
frame.init.bcntl = 1;
frame.init.data[0] = err;
- return queue_push(queue, (const uint8_t*)&frame);
+ return rust_usb_report_queue_push(queue, (const uint8_t*)&frame);
}
/**
diff --git a/src/usb/usb_frame.h b/src/usb/usb_frame.h
index 23ddef2..8bf3fed 100644
--- a/src/usb/usb_frame.h
+++ b/src/usb/usb_frame.h
@@ -5,7 +5,7 @@
#include <stdint.h>
-#include "queue.h"
+#include <rust/rust.h>
#include <usb/class/usb_size.h>
#define FRAME_TYPE_MASK 0x80 // Frame type mask
@@ -47,6 +47,7 @@
//
// With a packet size of 64 bytes (max for full-speed devices), this means that
// the maximum message payload length is 64 - 7 + 128 * (64 - 5) = 7609 bytes.
+// Keep this in sync with USB_DATA_MAX_LEN in src/rust/bitbox-usb-report-queue/src/lib.rs.
#define USB_DATA_MAX_LEN 7609U
#define HID_VENDOR_FIRST (FRAME_TYPE_INIT | 0x40) // First vendor defined command
@@ -91,12 +92,12 @@ typedef struct {
* @param[in] cid The channel ID.
* @param[in] add_frame_callback The callback to which the prepared frames are passed to.
*/
-queue_error_t usb_frame_reply(
+UsbReportQueueError usb_frame_reply(
uint8_t cmd,
const uint8_t* data,
uint32_t len,
uint32_t cid,
- struct queue* queue);
+ RustUsbReportQueue* queue);
/**
* Prepares an error USB frame, containing the channel id
@@ -105,7 +106,7 @@ queue_error_t usb_frame_reply(
* @param[in] err The error send to the host.
* @param[in] add_frame_callback The callback to which we add the frame.
*/
-queue_error_t usb_frame_prepare_err(uint8_t err, uint32_t cid, struct queue* queue);
+UsbReportQueueError usb_frame_prepare_err(uint8_t err, uint32_t cid, RustUsbReportQueue* queue);
/**
* Processes usb frame requests.
diff --git a/src/usb/usb_packet.c b/src/usb/usb_packet.c
index 2357fef..670ab90 100644
--- a/src/usb/usb_packet.c
+++ b/src/usb/usb_packet.c
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
#include "usb_packet.h"
-#include "queue.h"
#include "screen.h"
#include "usb_processing.h"
+#include <rust/rust.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -15,12 +15,17 @@
*/
static State _in_state;
+static RustUsbReportQueue* _out_queue(void)
+{
+ return usb_processing_out_queue(usb_processing_hww());
+}
+
/**
* Resets the current state.
*/
static void _reset_state(void)
{
- queue_clear(queue_hww_queue());
+ rust_usb_report_queue_clear(_out_queue());
memset(&_in_state, 0, sizeof(_in_state));
}
@@ -32,7 +37,7 @@ static void _reset_state(void)
*/
static void _queue_err(const uint8_t err, uint32_t cid)
{
- usb_frame_prepare_err(err, cid, queue_hww_queue());
+ usb_frame_prepare_err(err, cid, _out_queue());
}
static bool _need_more_data(void)
@@ -40,7 +45,7 @@ static bool _need_more_data(void)
return (_in_state.buf_ptr - _in_state.data) < (signed)_in_state.len;
}
-void usb_invalid_endpoint(struct queue* queue, uint32_t cid)
+void usb_invalid_endpoint(RustUsbReportQueue* queue, uint32_t cid)
{
// TODO: if U2F is disabled, we used to return a 'channel busy' command.
// now we return an invalid cmd, because there is not going to be a matching
diff --git a/src/usb/usb_packet.h b/src/usb/usb_packet.h
index 1967a54..aed8500 100644
--- a/src/usb/usb_packet.h
+++ b/src/usb/usb_packet.h
@@ -34,6 +34,6 @@ typedef struct {
*/
bool usb_packet_process(const USB_FRAME* frame);
-void usb_invalid_endpoint(struct queue* queue, uint32_t cid);
+void usb_invalid_endpoint(RustUsbReportQueue* queue, uint32_t cid);
#endif
diff --git a/src/usb/usb_processing.c b/src/usb/usb_processing.c
index acd263a..43ada05 100644
--- a/src/usb/usb_processing.c
+++ b/src/usb/usb_processing.c
@@ -8,6 +8,7 @@
#include "utils_assert.h"
#include <hardfault.h>
+#include <rust/rust.h>
#if !defined(BOOTLOADER)
#include <hww.h>
@@ -17,7 +18,6 @@ extern struct timer_descriptor TIMER_0;
#endif
#endif
-#include <queue.h>
#include <stdlib.h>
#include <string.h>
#include <u2f.h>
@@ -36,13 +36,13 @@ struct usb_processing {
uint32_t registered_cmds_len;
/* Whether the content of in_packet is a new, complete incoming packet. */
bool has_packet;
- struct queue* (*out_queue)(void);
+ RustUsbReportQueue* out_queue;
usb_frame_formatter_t format_frame;
/**
* Function to call when a message has been received,
* but there is no registered API set to manage it.
*/
- void (*manage_invalid_endpoint)(struct queue* queue, uint32_t cid);
+ void (*manage_invalid_endpoint)(RustUsbReportQueue* queue, uint32_t cid);
#if !defined(BOOTLOADER)
/**
* Function to call when a message has been received,
@@ -119,10 +119,10 @@ static usb_processing_state_t _usb_state = {0};
* Responds with data of a certain length.
* @param[in] packet The packet to be sent.
*/
-static queue_error_t _enqueue_frames(struct usb_processing* ctx, const Packet* out_packet)
+static UsbReportQueueError _enqueue_frames(struct usb_processing* ctx, const Packet* out_packet)
{
return ctx->format_frame(
- out_packet->cmd, out_packet->data_addr, out_packet->len, out_packet->cid, ctx->out_queue());
+ out_packet->cmd, out_packet->data_addr, out_packet->len, out_packet->cid, ctx->out_queue);
}
/**
@@ -239,7 +239,7 @@ static void _usb_execute_packet(struct usb_processing* ctx, const Packet* in_pac
if (!cmd_valid) {
util_log("usb_processing: No handler");
- ctx->manage_invalid_endpoint(ctx->out_queue(), _usb_state.in_packet.cid);
+ ctx->manage_invalid_endpoint(ctx->out_queue, _usb_state.in_packet.cid);
}
}
@@ -354,6 +354,11 @@ struct usb_processing* usb_processing_hww(void)
return &usb_processing;
}
+RustUsbReportQueue* usb_processing_out_queue(struct usb_processing* ctx)
+{
+ return ctx->out_queue;
+}
+
#if !defined(BOOTLOADER) && !defined(TESTING)
/**
* Callback invoked every 100ms from interrupt space.
@@ -380,25 +385,15 @@ static void _register_timer(void)
}
#endif
-void usb_processing_init(void)
+void usb_processing_init(RustUsbReportQueue* hww_queue)
{
-#if APP_U2F == 1
- usb_processing_u2f()->out_queue = queue_u2f_queue;
- queue_init(queue_u2f_queue(), USB_REPORT_SIZE);
- usb_processing_u2f()->format_frame = usb_frame_reply;
- usb_processing_u2f()->has_packet = false;
- usb_processing_u2f()->manage_invalid_endpoint = u2f_invalid_endpoint;
- usb_processing_u2f()->can_request_unblock = u2f_blocking_request_can_go_through;
- usb_processing_u2f()->create_blocked_req_error = u2f_blocked_req_error;
- usb_processing_u2f()->abort_outstanding_op = u2f_abort_outstanding_op;
-#endif
- usb_processing_hww()->out_queue = queue_hww_queue;
+ usb_processing_hww()->out_queue = hww_queue;
#if !defined(BOOTLOADER)
usb_processing_hww()->can_request_unblock = hww_blocking_request_can_go_through;
usb_processing_hww()->create_blocked_req_error = hww_blocked_req_error;
usb_processing_hww()->abort_outstanding_op = hww_abort_outstanding_op;
#endif
- queue_init(queue_hww_queue(), USB_REPORT_SIZE);
+ rust_usb_report_queue_clear(hww_queue);
usb_processing_hww()->format_frame = usb_frame_reply;
usb_processing_hww()->manage_invalid_endpoint = usb_invalid_endpoint;
usb_processing_hww()->has_packet = false;
@@ -407,6 +402,20 @@ void usb_processing_init(void)
#endif
}
+#if APP_U2F == 1
+void usb_processing_init_u2f(RustUsbReportQueue* u2f_queue)
+{
+ usb_processing_u2f()->out_queue = u2f_queue;
+ rust_usb_report_queue_clear(u2f_queue);
+ usb_processing_u2f()->format_frame = usb_frame_reply;
+ usb_processing_u2f()->has_packet = false;
+ usb_processing_u2f()->manage_invalid_endpoint = u2f_invalid_endpoint;
+ usb_processing_u2f()->can_request_unblock = u2f_blocking_request_can_go_through;
+ usb_processing_u2f()->create_blocked_req_error = u2f_blocked_req_error;
+ usb_processing_u2f()->abort_outstanding_op = u2f_abort_outstanding_op;
+}
+#endif
+
#if !defined(BOOTLOADER)
void usb_processing_lock(struct usb_processing* ctx)
{
diff --git a/src/usb/usb_processing.h b/src/usb/usb_processing.h
index e84066c..e4acf2d 100644
--- a/src/usb/usb_processing.h
+++ b/src/usb/usb_processing.h
@@ -3,7 +3,6 @@
#ifndef _USB_PROCESSING_H_
#define _USB_PROCESSING_H_
-#include "queue.h"
#include "usb_frame.h"
#include "usb_packet.h"
@@ -24,12 +23,12 @@ void usb_processing_register_cmds(
* Prepares USB frames to be send to the host.
* param[in] data The data is copied into one or more frames
*/
-typedef queue_error_t (*usb_frame_formatter_t)(
+typedef UsbReportQueueError (*usb_frame_formatter_t)(
const uint8_t cmd,
const uint8_t* data,
const uint32_t len,
const uint32_t cid,
- struct queue* queue);
+ RustUsbReportQueue* queue);
/**
* Enqueues a usb packet for processing. Ownership is transferred, and the
@@ -48,8 +47,13 @@ void usb_processing_process(struct usb_processing* ctx);
struct usb_processing* usb_processing_u2f(void);
struct usb_processing* usb_processing_hww(void);
+RustUsbReportQueue* usb_processing_out_queue(struct usb_processing* ctx);
-void usb_processing_init(void);
+void usb_processing_init(RustUsbReportQueue* hww_queue);
+
+#if APP_U2F == 1
+void usb_processing_init_u2f(RustUsbReportQueue* u2f_queue);
+#endif
#if !defined(BOOTLOADER)
void usb_processing_lock(struct usb_processing* ctx);
diff --git a/test/simulator-graphical-bb03/Cargo.lock b/test/simulator-graphical-bb03/Cargo.lock
index f1dba5e..d02af1a 100644
--- a/test/simulator-graphical-bb03/Cargo.lock
+++ b/test/simulator-graphical-bb03/Cargo.lock
@@ -391,6 +391,13 @@ dependencies = [
"cc",
]
+[[package]]
+name = "bitbox-usb-report-queue"
+version = "0.1.0"
+dependencies = [
+ "cortex-m",
+]
+
[[package]]
name = "bitbox02"
version = "0.1.0"
@@ -399,6 +406,7 @@ dependencies = [
"bitbox-bytequeue",
"bitbox-framed-serial-link",
"bitbox-hal",
+ "bitbox-usb-report-queue",
"bitbox02-noise",
"bitbox02-sys",
"futures-lite",
@@ -429,6 +437,7 @@ dependencies = [
"bitbox-executor",
"bitbox-hal",
"bitbox-secp256k1",
+ "bitbox-usb-report-queue",
"bitbox02",
"bitbox02-noise",
"bitcoin",
@@ -466,6 +475,7 @@ dependencies = [
"bitbox-da14531",
"bitbox-framed-serial-link",
"bitbox-hal",
+ "bitbox-usb-report-queue",
"bitbox02",
"bitbox02-noise",
"bitbox02-rust",
@@ -2945,6 +2955,7 @@ dependencies = [
"bitbox-aes",
"bitbox-hal",
"bitbox-lvgl",
+ "bitbox-usb-report-queue",
"bitbox02-rust",
"bitbox02-rust-c",
"bitbox03",
diff --git a/test/simulator-graphical-bb03/Cargo.toml b/test/simulator-graphical-bb03/Cargo.toml
index 87da173..98a2e28 100644
--- a/test/simulator-graphical-bb03/Cargo.toml
+++ b/test/simulator-graphical-bb03/Cargo.toml
@@ -4,8 +4,9 @@ version = "0.1.0"
edition = "2024"
[dependencies]
-bitbox02-rust = { path = "../../src/rust/bitbox02-rust", features = ["simulator-graphical"] }
bitbox-hal = { path = "../../src/rust/bitbox-hal" }
+bitbox-usb-report-queue = { path = "../../src/rust/bitbox-usb-report-queue" }
+bitbox02-rust = { path = "../../src/rust/bitbox02-rust", features = ["simulator-graphical"] }
bitbox02-rust-c = { path = "../../src/rust/bitbox02-rust-c", features = ["simulator-graphical"] }
bitbox-aes = { path = "../../src/rust/bitbox-aes" }
winit = "0.30.12"
diff --git a/test/simulator-graphical-bb03/src/main.rs b/test/simulator-graphical-bb03/src/main.rs
index 0eaabba..336acd2 100644
--- a/test/simulator-graphical-bb03/src/main.rs
+++ b/test/simulator-graphical-bb03/src/main.rs
@@ -40,6 +40,7 @@ use tracing_subscriber::{EnvFilter, filter::LevelFilter, fmt, prelude::*};
use bitbox_hal::{Hal, Ui};
+use bitbox_usb_report_queue::UsbReportQueue;
use bitbox03::BitBox03;
use bitbox03::io::touchscreen::{TouchScreen, TouchScreenEvent};
@@ -201,9 +202,9 @@ fn my_flush_cb(display: lvgl::LvDisplay, _area: &lvgl::LvArea, _px_map: *mut u8)
}
}
-fn init_hww(_bitbox: &mut BitBox03, preseed: bool) -> bool {
+fn init_hww(_bitbox: &mut BitBox03, preseed: bool, _hww_queue: &mut UsbReportQueue) -> bool {
// BitBox02 simulation initialization
- //bitbox02::usb_processing::init();
+ //bitbox02::usb_processing::init(hww_queue);
info!("USB setup success");
//bitbox02::hww::setup();
@@ -245,6 +246,7 @@ struct App {
inbound_out: Option<mpsc::Receiver<[u8; 64]>>,
startup_task: Option<util::bb02_async::Task<'static, ()>>,
counter: usize,
+ hww_queue: UsbReportQueue,
}
impl App {
@@ -264,6 +266,7 @@ impl App {
inbound_out: Default::default(),
startup_task: Default::default(),
counter: 0,
+ hww_queue: Default::default(),
}
}
}
@@ -630,18 +633,18 @@ impl ApplicationHandler<UserEvent> for App {
self.inbound_out = inbound_out;
}
// Send data to TCP Client
- //loop {
- // if let Some(data) = bitbox02::queue::pull_hww() {
- // if let Some(outbound_in) = &mut self.outbound_in {
- // if outbound_in.send(data).is_err() {
- // info!("writer thread died and closed channel");
- // let _ = self.outbound_in.take();
- // }
- // }
- // } else {
- // break;
- // }
- //}
+ loop {
+ if let Some(data) = self.hww_queue.pull() {
+ if let Some(outbound_in) = &mut self.outbound_in {
+ if outbound_in.send(data).is_err() {
+ info!("writer thread died and closed channel");
+ let _ = self.outbound_in.take();
+ }
+ }
+ } else {
+ break;
+ }
+ }
// Business logic
bitbox02_rust::async_usb::spin();
//bitbox02::usb_processing::process_hww();
@@ -714,7 +717,8 @@ pub fn main() -> Result<(), Box<dyn Error>> {
let args = Args::parse();
- if !init_hww(&mut bitbox, args.preseed) {
+ let mut app = App::new(bitbox);
+ if !init_hww(&mut bitbox, args.preseed, &mut app.hww_queue) {
return Err(Box::new(AppError::new("Failed to init hww")));
}
let event_loop = EventLoop::<UserEvent>::with_user_event().build()?;
@@ -785,7 +789,6 @@ pub fn main() -> Result<(), Box<dyn Error>> {
}
});
- let mut app = App::new(bitbox);
event_loop.run_app(&mut app)?;
Ok(())
diff --git a/test/simulator-graphical/Cargo.lock b/test/simulator-graphical/Cargo.lock
index ab78306..e5c3134 100644
--- a/test/simulator-graphical/Cargo.lock
+++ b/test/simulator-graphical/Cargo.lock
@@ -335,6 +335,13 @@ dependencies = [
"cc",
]
+[[package]]
+name = "bitbox-usb-report-queue"
+version = "0.1.0"
+dependencies = [
+ "cortex-m",
+]
+
[[package]]
name = "bitbox02"
version = "0.1.0"
@@ -343,6 +350,7 @@ dependencies = [
"bitbox-bytequeue",
"bitbox-framed-serial-link",
"bitbox-hal",
+ "bitbox-usb-report-queue",
"bitbox02-noise",
"bitbox02-sys",
"futures-lite",
@@ -373,6 +381,7 @@ dependencies = [
"bitbox-executor",
"bitbox-hal",
"bitbox-secp256k1",
+ "bitbox-usb-report-queue",
"bitbox02",
"bitbox02-noise",
"bitcoin",
@@ -410,6 +419,7 @@ dependencies = [
"bitbox-da14531",
"bitbox-framed-serial-link",
"bitbox-hal",
+ "bitbox-usb-report-queue",
"bitbox02",
"bitbox02-noise",
"bitbox02-rust",
@@ -2844,6 +2854,7 @@ name = "simulator-graphical"
version = "0.1.0"
dependencies = [
"bitbox-aes",
+ "bitbox-usb-report-queue",
"bitbox02",
"bitbox02-rust",
"bitbox02-rust-c",
diff --git a/test/simulator-graphical/Cargo.toml b/test/simulator-graphical/Cargo.toml
index 8bd3a07..ceabdca 100644
--- a/test/simulator-graphical/Cargo.toml
+++ b/test/simulator-graphical/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2024"
bitbox02-rust = { path="../../src/rust/bitbox02-rust", features=["simulator-graphical"] }
bitbox02-rust-c = { path="../../src/rust/bitbox02-rust-c", features=["simulator-graphical"] }
bitbox02 = { path="../../src/rust/bitbox02", features=["simulator-graphical"] }
+bitbox-usb-report-queue = { path = "../../src/rust/bitbox-usb-report-queue" }
bitbox-aes = { path="../../src/rust/bitbox-aes"}
winit = "0.30.12"
tracing = {version = "0.1.41", features=["log"]}
diff --git a/test/simulator-graphical/src/main.rs b/test/simulator-graphical/src/main.rs
index 5b4c041..55e3c58 100644
--- a/test/simulator-graphical/src/main.rs
+++ b/test/simulator-graphical/src/main.rs
@@ -38,6 +38,7 @@ use glutin_winit::DisplayBuilder;
use tracing::{debug, error, info};
use tracing_subscriber::{EnvFilter, filter::LevelFilter, fmt, prelude::*};
+use bitbox_usb_report_queue::UsbReportQueue;
use bitbox02::ui::ugui::UG_COLOR;
use bitbox02_rust::hal::{Eeprom, Hal, Memory, System};
@@ -137,12 +138,12 @@ fn mirror_fn(_: bool) {
static ACCEPTING_CONNECTIONS: AtomicBool = AtomicBool::new(false);
-fn init_hww(preseed: bool) -> bool {
+fn init_hww(preseed: bool, hww_queue: &mut UsbReportQueue) -> bool {
bitbox02::screen::init(pixel_fn, mirror_fn, clear_fn);
bitbox02::screen::splash();
// BitBox02 simulation initialization
- bitbox02::usb_processing::init();
+ bitbox02::usb_processing::init(hww_queue);
info!("USB setup success");
bitbox02::hww::setup();
@@ -222,6 +223,7 @@ struct App {
outbound_in: Option<mpsc::Sender<[u8; 64]>>,
inbound_out: Option<mpsc::Receiver<[u8; 64]>>,
startup_task: Option<util::bb02_async::Task<'static, ()>>,
+ hww_queue: UsbReportQueue,
}
impl Default for App {
@@ -241,6 +243,7 @@ impl Default for App {
outbound_in: Default::default(),
inbound_out: Default::default(),
startup_task: Default::default(),
+ hww_queue: Default::default(),
}
}
}
@@ -644,7 +647,7 @@ impl ApplicationHandler<UserEvent> for App {
}
// Send data to TCP Client
loop {
- if let Some(data) = bitbox02::queue::pull_hww() {
+ if let Some(data) = self.hww_queue.pull() {
if let Some(outbound_in) = &mut self.outbound_in {
if outbound_in.send(data).is_err() {
info!("writer thread died and closed channel");
@@ -735,7 +738,8 @@ pub fn main() -> Result<(), Box<dyn Error>> {
let args = Args::parse();
- if !init_hww(args.preseed) {
+ let mut app = App::default();
+ if !init_hww(args.preseed, &mut app.hww_queue) {
return Err(Box::new(AppError::new("Failed to init hww")));
}
let event_loop = EventLoop::<UserEvent>::with_user_event().build()?;
@@ -806,7 +810,6 @@ pub fn main() -> Result<(), Box<dyn Error>> {
}
});
- let mut app = App::default();
event_loop.run_app(&mut app)?;
Ok(())
diff --git a/test/simulator/simulator.c b/test/simulator/simulator.c
index c2ccf6b..947c607 100644
--- a/test/simulator/simulator.c
+++ b/test/simulator/simulator.c
@@ -8,7 +8,6 @@
#include <fcntl.h>
#include <memory/memory.h>
#include <memory/memory_shared.h>
-#include <queue.h>
#include <random.h>
#include <rust/rust.h>
#include <sd.h>
@@ -39,16 +38,15 @@ static int get_usb_message_socket(uint8_t* input)
return read(commfd, input, USB_HID_REPORT_OUT_SIZE);
}
-static void send_usb_message_socket(void)
+static void send_usb_message_socket(RustUsbReportQueue* hww_queue)
{
- const uint8_t* data = queue_pull(queue_hww_queue());
- while (data) {
+ uint8_t data[USB_REPORT_SIZE];
+ while (rust_usb_report_queue_pull(hww_queue, data)) {
data_len = 256 * (int)data[5] + (int)data[6];
if (!write(commfd, data, USB_HID_REPORT_OUT_SIZE)) {
perror("ERROR, could not write to socket");
exit(1);
}
- data = queue_pull(queue_hww_queue());
}
}
@@ -107,7 +105,12 @@ int main(int argc, char* argv[])
}
// BitBox02 simulation initialization
- usb_processing_init();
+ RustUsbReportQueue* hww_queue = rust_usb_report_queue_init();
+ if (hww_queue == NULL) {
+ perror("ERROR, could not allocate HWW queue");
+ return 1;
+ }
+ usb_processing_init(hww_queue);
printf("USB setup success\n");
hww_setup();
@@ -215,10 +218,10 @@ int main(int argc, char* argv[])
// input, then it does not consume any packets but it still calls
// the send function to send further USB messages
usb_processing_process(usb_processing_hww());
- send_usb_message_socket();
+ send_usb_message_socket(hww_queue);
temp_len -= (USB_HID_REPORT_OUT_SIZE - 5);
}
- send_usb_message_socket();
+ send_usb_message_socket(hww_queue);
}
close(commfd);
printf("Socket connection closed\n");
@@ -226,5 +229,6 @@ int main(int argc, char* argv[])
}
after_main_loop:
close(sockfd);
+ rust_usb_report_queue_free(hww_queue);
return 0;
}
diff --git a/test/unit-test/framework/src/mock_hidapi.c b/test/unit-test/framework/src/mock_hidapi.c
index 821c54f..9222f73 100644
--- a/test/unit-test/framework/src/mock_hidapi.c
+++ b/test/unit-test/framework/src/mock_hidapi.c
@@ -1,6 +1,7 @@
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <util.h>
@@ -10,10 +11,10 @@
#include <hidapi.h>
-#include "queue.h"
#include "u2f.h"
#include "u2f/u2f_packet.h"
#include "usb/usb_processing.h"
+#include <rust/rust.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
@@ -29,6 +30,10 @@ static pthread_t thread;
static bool timer_thread_stop;
static pthread_mutex_t mutex;
+struct mock_hid_device {
+ RustUsbReportQueue* u2f_queue;
+};
+
static void _delay(uint32_t msec)
{
struct timespec rem;
@@ -72,6 +77,7 @@ int hid_init(void)
void hid_close(hid_device* dev)
{
+ struct mock_hid_device* mock_dev = (struct mock_hid_device*)dev;
pthread_mutex_lock(&mutex);
timer_thread_stop = true;
pthread_mutex_unlock(&mutex);
@@ -80,12 +86,25 @@ void hid_close(hid_device* dev)
if (res != 0) {
printf("Failed to join thread\n");
}
+ rust_usb_report_queue_free(mock_dev->u2f_queue);
+ free(mock_dev);
}
hid_device* hid_open_path(const char* path)
{
- static char sham[] = "sham";
- usb_processing_init();
+ (void)path;
+ struct mock_hid_device* mock_dev = malloc(sizeof(*mock_dev));
+ if (mock_dev == NULL) {
+ printf("failed to allocate mock hid device\n");
+ return NULL;
+ }
+ mock_dev->u2f_queue = rust_usb_report_queue_init();
+ if (mock_dev->u2f_queue == NULL) {
+ printf("failed to allocate U2F queue\n");
+ free(mock_dev);
+ return NULL;
+ }
+ usb_processing_init_u2f(mock_dev->u2f_queue);
u2f_device_setup();
timer_thread_stop = false;
int res = pthread_create(&thread, NULL, &timer_task, NULL);
@@ -93,11 +112,12 @@ hid_device* hid_open_path(const char* path)
printf("failed to create thread\n");
}
pthread_mutex_init(&mutex, NULL);
- return (hid_device*)&sham;
+ return (hid_device*)mock_dev;
}
int hid_write(hid_device* dev, const unsigned char* data, size_t length)
{
+ (void)dev;
if (length > BUFSIZE + 1) {
printf("Internal test error: %lu > %lu\n", length - 1, BUFSIZE);
return 0;
@@ -115,6 +135,8 @@ int hid_write(hid_device* dev, const unsigned char* data, size_t length)
int hid_read_timeout(hid_device* dev, unsigned char* data, size_t length, int milliseconds)
{
+ struct mock_hid_device* mock_dev = (struct mock_hid_device*)dev;
+ (void)milliseconds;
if (_expect_more || !_have_data) {
if (_expect_more) {
// printf("Internal error: expected more before read\n");
@@ -126,16 +148,17 @@ int hid_read_timeout(hid_device* dev, unsigned char* data, size_t length, int mi
usb_processing_process(usb_processing_u2f());
}
usb_processing_process(usb_processing_u2f());
- uint8_t* p = queue_pull(queue_u2f_queue());
- // printf("Queue: %p\n", p);
- if (p != NULL) {
- memcpy(data, p, MIN(length, BUFSIZE));
+ uint8_t report[USB_REPORT_SIZE];
+ bool have_report = rust_usb_report_queue_pull(mock_dev->u2f_queue, report);
+ // printf("Queue: %d\n", have_report);
+ if (have_report) {
+ memcpy(data, report, MIN(length, BUFSIZE));
} else {
// printf("No data in queue\n");
_delay(600);
return -127;
}
- if (queue_peek(queue_u2f_queue()) == NULL) {
+ if (!rust_usb_report_queue_peek(mock_dev->u2f_queue, report)) {
if (usb_processing_locked(usb_processing_u2f())) {
usb_processing_unlock();
}
diff --git a/test/unit-test/test_simulator.c b/test/unit-test/test_simulator.c
index b932ea1..5a59b4e 100644
--- a/test/unit-test/test_simulator.c
+++ b/test/unit-test/test_simulator.c
@@ -9,7 +9,6 @@
#include <fcntl.h>
#include <memory/memory.h>
#include <mock_memory.h>
-#include <queue.h>
#include <random.h>
#include <rust/rust.h>
#include <sd.h>
@@ -30,16 +29,15 @@ int get_usb_message_socket(uint8_t* input)
return read(sockfd, input, USB_HID_REPORT_OUT_SIZE);
}
-void send_usb_message_socket(void)
+void send_usb_message_socket(RustUsbReportQueue* hww_queue)
{
- const uint8_t* data = queue_pull(queue_hww_queue());
- while (data) {
+ uint8_t data[USB_REPORT_SIZE];
+ while (rust_usb_report_queue_pull(hww_queue, data)) {
data_len = 256 * (int)data[5] + (int)data[6];
if (!write(sockfd, data, USB_HID_REPORT_OUT_SIZE)) {
perror("ERROR, could not write to socket");
exit(1);
}
- data = queue_pull(queue_hww_queue());
}
}
@@ -75,7 +73,12 @@ int main(void)
}
// BitBox02 simulation initializaition
- usb_processing_init();
+ RustUsbReportQueue* hww_queue = rust_usb_report_queue_init();
+ if (hww_queue == NULL) {
+ perror("ERROR, could not allocate HWW queue");
+ return 1;
+ }
+ usb_processing_init(hww_queue);
printf("USB setup success\n");
hww_setup();
@@ -122,8 +125,9 @@ int main(void)
usb_processing_process(usb_processing_hww());
temp_len -= (USB_HID_REPORT_OUT_SIZE - 5);
}
- send_usb_message_socket();
+ send_usb_message_socket(hww_queue);
}
close(sockfd);
+ rust_usb_report_queue_free(hww_queue);
return 0;
}
diff --git a/test/unit-test/test_u2f_standard.c b/test/unit-test/test_u2f_standard.c
index 27e0196..a68dfe9 100644
--- a/test/unit-test/test_u2f_standard.c
+++ b/test/unit-test/test_u2f_standard.c
@@ -36,7 +36,7 @@ U2F_REGISTER_REQ regReq;
U2F_REGISTER_RESP regRsp;
U2F_AUTHENTICATE_REQ authReq;
-static void util_uint8_to_hex(const uint8_t* in_bin, const size_t in_len, char* out)
+static void test_u2f_standard_uint8_to_hex(const uint8_t* in_bin, const size_t in_len, char* out)
{
static char digits[] = "0123456789abcdef";
size_t i;
@@ -163,7 +163,7 @@ static void test_Enroll(int expectedSW12, int printinfo)
CHECK_EQ(getCertificate(regRsp, cert, &cert_len), true);
if (printinfo) {
char buf[cert_len * 2 + 1];
- util_uint8_to_hex((uint8_t*)cert, cert_len, buf);
+ test_u2f_standard_uint8_to_hex((uint8_t*)cert, cert_len, buf);
PRINT_INFO("Certificate: %lu %s", cert_len, buf);
}
@@ -172,7 +172,7 @@ static void test_Enroll(int expectedSW12, int printinfo)
CHECK_EQ(getSubjectPublicKey(cert, cert_len, pk, &pk_len), true);
if (printinfo) {
char buf[pk_len * 2 + 1];
- util_uint8_to_hex((uint8_t*)pk, pk_len, buf);
+ test_u2f_standard_uint8_to_hex((uint8_t*)pk, pk_len, buf);
PRINT_INFO("Public key: %lu %s", pk_len, buf);
}
CHECK_EQ(pk_len, (size_t)U2F_EC_POINT_SIZE);
@@ -182,7 +182,7 @@ static void test_Enroll(int expectedSW12, int printinfo)
CHECK_EQ(getSignature(regRsp, sig, &sig_len), true);
if (printinfo) {
char buf[sig_len * 2 + 1];
- util_uint8_to_hex((uint8_t*)sig, sig_len, buf);
+ test_u2f_standard_uint8_to_hex((uint8_t*)sig, sig_len, buf);
PRINT_INFO("Signature: %lu %s", sig_len, buf);
}
diff --git a/test/unit-test/u2f/u2f_util_t.c b/test/unit-test/u2f/u2f_util_t.c
index 83c2d9d..bf8d9b4 100644
--- a/test/unit-test/u2f/u2f_util_t.c
+++ b/test/unit-test/u2f/u2f_util_t.c
@@ -36,7 +36,7 @@
_a > _b ? _a : _b; \
})
-static void util_uint8_to_hex(const uint8_t* in_bin, const size_t in_len, char* out)
+static void u2f_util_uint8_to_hex(const uint8_t* in_bin, const size_t in_len, char* out)
{
static char digits[] = "0123456789abcdef";
size_t i;
@@ -517,7 +517,7 @@ bool getSubjectPublicKey(const char* cert, size_t cert_len, char* pk, size_t* pk
char cert_c[cert_len * 2 + 1];
char* cert_c_p = cert_c;
- util_uint8_to_hex((const uint8_t*)cert, cert_len, cert_c);
+ u2f_util_uint8_to_hex((const uint8_t*)cert, cert_len, cert_c);
// memcpy(cert_c, utils_uint8_to_hex((const uint8_t *)cert, cert_len), cert_len * 2);
char* pkStart = strstr(cert_c, asn1);
@@ -540,7 +540,7 @@ bool getCertSignature(const char* cert, size_t cert_len, char* sig, size_t* sig_
const char asn1[] = "300906072a8648ce3d040103";
char cert_c[cert_len * 2 + 1];
char* cert_c_p = cert_c;
- util_uint8_to_hex((const uint8_t*)cert, cert_len, cert_c);
+ u2f_util_uint8_to_hex((const uint8_t*)cert, cert_len, cert_c);
// memcpy(cert_c, utils_uint8_to_hex((const uint8_t *)cert, cert_len), cert_len * 2);
char* pkStart = strstr(cert_c, asn1);
Why this scored 34/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.