From 63e9faf82dbf8b38d21cc65e66e632c0d79ecb48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dav=C3=AD=C3=B0=20Steinn=20Geirsson?= Date: Sun, 22 Mar 2026 11:13:45 +0000 Subject: [PATCH] fix: align bulk IN buffers and forward unknown string descriptors Two fixes for mass storage passthrough: 1. Bulk IN buffer allocation now rounds up to the endpoint's max_packet_size. nusb (and the USB spec) require IN transfers to be multiples of max_packet_size. Without this, SCSI INQUIRY (36 bytes on a 512-byte max_packet_size endpoint) was rejected, causing the kernel to repeatedly reset the device. 2. String descriptor requests for indices not in the local string pool are now forwarded to the device handler. This fixes interface and configuration string descriptors (e.g., iInterface=5) that exist on the real device but weren't populated in the synthetic string pool. Tested: USB mass storage gadget via dummy_hcd successfully enumerates, mounts, reads, and writes through the USBIP passthrough. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/src/device.rs | 12 ++++++++++++ lib/src/host.rs | 7 +++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/src/device.rs b/lib/src/device.rs index 3b5a953..64af853 100644 --- a/lib/src/device.rs +++ b/lib/src/device.rs @@ -507,6 +507,18 @@ impl UsbDevice { desc.resize(setup_packet.length as usize, 0); } Ok(UrbResponse { data: desc, ..Default::default() }) + } else if self.device_handler.is_some() { + // Forward unknown string indices to the device handler + // (host passthrough: the real device knows its own strings) + let lock = self.device_handler.as_ref().unwrap(); + let mut handler = lock.lock().unwrap(); + handler.handle_urb(UrbRequest { + ep, + transfer_buffer_length, + setup: setup_packet, + data: out_data, + ..Default::default() + }) } else { Err(std::io::Error::new( std::io::ErrorKind::InvalidInput, diff --git a/lib/src/host.rs b/lib/src/host.rs index 048ba5f..6dffc70 100644 --- a/lib/src/host.rs +++ b/lib/src/host.rs @@ -334,17 +334,20 @@ impl UsbInterfaceHandler for NusbUsbHostInterfaceHandler { } else if ep.attributes == EndpointAttributes::Bulk as u8 { // bulk if let Direction::In = ep.direction() { - // bulk in + // bulk in - round up to max_packet_size as required by USB spec + let mps = ep.max_packet_size.max(1) as usize; + let alloc_len = ((transfer_buffer_length as usize) + mps - 1) / mps * mps; let mut endpoint = handle .endpoint::(ep.address) .map_err(|e| { std::io::Error::other(format!("Failed to open bulk endpoint: {}", e)) })?; - let buffer = endpoint.allocate(transfer_buffer_length as usize); + let buffer = endpoint.allocate(alloc_len); let completion = endpoint.transfer_blocking(buffer, timeout); completion.status.map_err(|e| { std::io::Error::new(std::io::ErrorKind::Other, format!("USB bulk IN failed: {e}")) })?; + // Return only the actual bytes received (may be less than alloc_len) return Ok(UrbResponse { data: completion.buffer.to_vec(), ..Default::default() }); } else { // bulk out