diff --git a/bin/usb-client b/bin/usb-client index fa36f0b..61ca710 100755 Binary files a/bin/usb-client and b/bin/usb-client differ diff --git a/bin/usb-relay b/bin/usb-relay index 6d6fdb8..b66ed2f 100755 Binary files a/bin/usb-relay and b/bin/usb-relay differ diff --git a/internal/usbip/protocol.go b/internal/usbip/protocol.go index 5ec7836..4ed5800 100644 --- a/internal/usbip/protocol.go +++ b/internal/usbip/protocol.go @@ -267,8 +267,11 @@ func BuildImportReply(status uint32, dev *DeviceDescriptor) ([]byte, error) { return buf.Bytes(), nil } -// BuildRetSubmit builds a RET_SUBMIT message -func BuildRetSubmit(seqNum, devID, direction, endpoint uint32, status int32, data []byte) ([]byte, error) { +// BuildRetSubmit builds a RET_SUBMIT message. +// actualLength must be set for BOTH directions: it reports how many bytes +// were actually transferred. For OUT transfers the kernel driver checks this +// (e.g. UVC probe control expects actualLength == 26). +func BuildRetSubmit(seqNum, devID, direction, endpoint uint32, status int32, actualLength uint32, data []byte) ([]byte, error) { buf := &bytes.Buffer{} hdr := &URBHeader{ @@ -282,14 +285,9 @@ func BuildRetSubmit(seqNum, devID, direction, endpoint uint32, status int32, dat return nil, err } - actualLen := uint32(0) - if direction == DirIn && data != nil { - actualLen = uint32(len(data)) - } - body := &RetSubmitBody{ Status: status, - ActualLength: actualLen, + ActualLength: actualLength, NumberOfPackets: 0xFFFFFFFF, } if err := WriteRetSubmit(buf, body); err != nil { @@ -307,7 +305,7 @@ func BuildRetSubmit(seqNum, devID, direction, endpoint uint32, status int32, dat // BuildRetSubmitISO builds a RET_SUBMIT message for isochronous transfers. // The transfer data must already be packed (compact, no gaps). func BuildRetSubmitISO(seqNum, devID, direction, endpoint uint32, status int32, - packedData []byte, startFrame uint32, numPackets int32, errorCount int32, + actualLength uint32, packedData []byte, startFrame uint32, numPackets int32, errorCount int32, isoDescs []ISOPacketDescriptor) ([]byte, error) { buf := &bytes.Buffer{} @@ -323,14 +321,9 @@ func BuildRetSubmitISO(seqNum, devID, direction, endpoint uint32, status int32, return nil, err } - actualLen := uint32(0) - if direction == DirIn && packedData != nil { - actualLen = uint32(len(packedData)) - } - body := &RetSubmitBody{ Status: status, - ActualLength: actualLen, + ActualLength: actualLength, StartFrame: startFrame, NumberOfPackets: uint32(numPackets), ErrorCount: uint32(errorCount), diff --git a/internal/usbip/server.go b/internal/usbip/server.go index f00c5cd..e06d593 100644 --- a/internal/usbip/server.go +++ b/internal/usbip/server.go @@ -372,7 +372,7 @@ func (s *Server) handleCmdSubmit(r io.Reader, hdr *URBHeader, retChan chan<- []b status = -32 // -EPIPE n = 0 } - resp, err := BuildRetSubmit(hdr.SeqNum, hdr.DevID, hdr.Direction, hdr.Endpoint, status, buf[:n]) + resp, err := BuildRetSubmit(hdr.SeqNum, hdr.DevID, hdr.Direction, hdr.Endpoint, status, uint32(n), buf[:n]) if err != nil { return err } @@ -387,6 +387,7 @@ func (s *Server) handleCmdSubmit(r io.Reader, hdr *URBHeader, retChan chan<- []b wIndex := binary.LittleEndian.Uint16(body.Setup[4:6]) var status int32 + var actualLength uint32 // Intercept standard USB requests that require special usbdevfs ioctls. // Raw control transfers via USBDEVFS_CONTROL don't update kernel state. @@ -415,7 +416,7 @@ func (s *Server) handleCmdSubmit(r io.Reader, hdr *URBHeader, retChan chan<- []b if buf == nil { buf = make([]byte, 0) } - _, err := s.handle.ControlTransfer( + n, err := s.handle.ControlTransfer( bmRequestType, bRequest, wValue, wIndex, binary.LittleEndian.Uint16(body.Setup[6:8]), 5000, buf, @@ -424,13 +425,14 @@ func (s *Server) handleCmdSubmit(r io.Reader, hdr *URBHeader, retChan chan<- []b log.Printf("[usbip-server] CTRL OUT seq=%d failed: %v", hdr.SeqNum, err) status = -32 // -EPIPE } else { - log.Printf("[usbip-server] CTRL OUT seq=%d OK (bmReqType=0x%02x bReq=0x%02x wVal=0x%04x)", - hdr.SeqNum, bmRequestType, bRequest, wValue) + actualLength = uint32(n) + log.Printf("[usbip-server] CTRL OUT seq=%d OK actualLength=%d (bmReqType=0x%02x bReq=0x%02x wVal=0x%04x)", + hdr.SeqNum, n, bmRequestType, bRequest, wValue) } } - log.Printf("[usbip-server] CTRL OUT seq=%d → response status=%d", hdr.SeqNum, status) - resp, err := BuildRetSubmit(hdr.SeqNum, hdr.DevID, hdr.Direction, hdr.Endpoint, status, nil) + log.Printf("[usbip-server] CTRL OUT seq=%d → response status=%d actualLength=%d", hdr.SeqNum, status, actualLength) + resp, err := BuildRetSubmit(hdr.SeqNum, hdr.DevID, hdr.Direction, hdr.Endpoint, status, actualLength, nil) if err != nil { return err } @@ -468,7 +470,7 @@ func (s *Server) handleCmdSubmit(r io.Reader, hdr *URBHeader, retChan chan<- []b }) if err != nil { log.Printf("[usbip-server] SubmitURB(ep=0x%02x, type=%d, len=%d) FAILED: %v", ep, urbType, len(buf), err) - resp, _ := BuildRetSubmit(hdr.SeqNum, hdr.DevID, hdr.Direction, hdr.Endpoint, -32, nil) + resp, _ := BuildRetSubmit(hdr.SeqNum, hdr.DevID, hdr.Direction, hdr.Endpoint, -32, 0, nil) retChan <- resp return nil } @@ -535,7 +537,7 @@ func (s *Server) handleISOSubmit(hdr *URBHeader, body *CmdSubmitBody, transferBu if err != nil { log.Printf("[usbip-server] ISO submit FAILED: %v", err) // Submit failed - send error response - resp, _ := BuildRetSubmit(hdr.SeqNum, hdr.DevID, hdr.Direction, hdr.Endpoint, -32, nil) + resp, _ := BuildRetSubmit(hdr.SeqNum, hdr.DevID, hdr.Direction, hdr.Endpoint, -32, 0, nil) retChan <- resp return nil } @@ -653,6 +655,7 @@ func (s *Server) reapLoop(retChan chan<- []byte, done <-chan struct{}) { pending.direction, pending.endpoint, urbInfo.Status, + uint32(urbInfo.ActualLength), data, ) } @@ -708,6 +711,7 @@ func (s *Server) buildISOResponse(urbInfo *usb.ReapedURBInfo, pending *pendingUR pending.direction, pending.endpoint, urbInfo.Status, + uint32(urbInfo.ActualLength), packedData, uint32(urbInfo.StartFrame), pending.numPackets,