360 lines
9.8 KiB
Go
360 lines
9.8 KiB
Go
package usbip
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestUSBIPSubmitCommandRoundTripOut(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
expected := SubmitCommand{
|
|
Header: DataHeader{
|
|
Command: CmdSubmit,
|
|
SeqNum: 7,
|
|
DevID: 0x00030009,
|
|
Direction: USBIPDirOut,
|
|
Endpoint: 2,
|
|
},
|
|
TransferFlags: 0x400,
|
|
TransferBufferLength: 3,
|
|
StartFrame: 11,
|
|
NumberOfPackets: nonIsoPacketCount,
|
|
Interval: 4,
|
|
Setup: [8]byte{0, 1, 2, 3, 4, 5, 6, 7},
|
|
Buffer: []byte{1, 2, 3},
|
|
}
|
|
|
|
var buffer bytes.Buffer
|
|
require.NoError(t, WriteSubmitCommand(&buffer, expected))
|
|
|
|
header, err := ReadDataHeader(&buffer)
|
|
require.NoError(t, err)
|
|
require.Equal(t, expected.Header, header)
|
|
|
|
actual, err := ReadSubmitCommandBody(&buffer, header)
|
|
require.NoError(t, err)
|
|
require.Equal(t, expected, actual)
|
|
}
|
|
|
|
func TestUSBIPSubmitCommandRoundTripInOmitsCommandPayload(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
expected := SubmitCommand{
|
|
Header: DataHeader{
|
|
Command: CmdSubmit,
|
|
SeqNum: 8,
|
|
DevID: 0x00030009,
|
|
Direction: USBIPDirIn,
|
|
Endpoint: 1,
|
|
},
|
|
TransferBufferLength: 4,
|
|
NumberOfPackets: nonIsoPacketCount,
|
|
}
|
|
|
|
var buffer bytes.Buffer
|
|
require.NoError(t, WriteSubmitCommand(&buffer, expected))
|
|
require.Equal(t, dataHeaderSize, buffer.Len())
|
|
|
|
header, err := ReadDataHeader(&buffer)
|
|
require.NoError(t, err)
|
|
actual, err := ReadSubmitCommandBody(&buffer, header)
|
|
require.NoError(t, err)
|
|
require.Equal(t, expected.Header, actual.Header)
|
|
require.Equal(t, expected.TransferBufferLength, actual.TransferBufferLength)
|
|
require.Empty(t, actual.Buffer)
|
|
}
|
|
|
|
func TestUSBIPSubmitResponseRoundTripInWithIsoPackets(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
expected := SubmitResponse{
|
|
Header: DataHeader{
|
|
Command: RetSubmit,
|
|
SeqNum: 9,
|
|
DevID: 0x00030009,
|
|
Direction: USBIPDirIn,
|
|
Endpoint: 3,
|
|
},
|
|
Status: 0,
|
|
ActualLength: 4,
|
|
StartFrame: 21,
|
|
NumberOfPackets: 2,
|
|
ErrorCount: 1,
|
|
Buffer: []byte{9, 8, 7, 6},
|
|
IsoPackets: []IsoPacketDescriptor{
|
|
{Offset: 0, Length: 2, ActualLength: 2, Status: 0},
|
|
{Offset: 2, Length: 2, ActualLength: 1, Status: -32},
|
|
},
|
|
}
|
|
|
|
var buffer bytes.Buffer
|
|
require.NoError(t, WriteSubmitResponse(&buffer, expected))
|
|
|
|
header, err := ReadDataHeader(&buffer)
|
|
require.NoError(t, err)
|
|
require.Equal(t, DataHeader{Command: RetSubmit, SeqNum: expected.Header.SeqNum}, header)
|
|
|
|
actual, err := ReadSubmitResponseBody(&buffer, header, expected.Header.Direction)
|
|
require.NoError(t, err)
|
|
expected.Header = DataHeader{Command: RetSubmit, SeqNum: expected.Header.SeqNum}
|
|
require.Equal(t, expected, actual)
|
|
}
|
|
|
|
func TestUSBIPSubmitResponseRoundTripOutOmitsResponsePayload(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
expected := SubmitResponse{
|
|
Header: DataHeader{
|
|
Command: RetSubmit,
|
|
SeqNum: 10,
|
|
DevID: 0x00030009,
|
|
Direction: USBIPDirOut,
|
|
Endpoint: 2,
|
|
},
|
|
Status: 0,
|
|
ActualLength: 3,
|
|
NumberOfPackets: nonIsoPacketCount,
|
|
}
|
|
|
|
var buffer bytes.Buffer
|
|
require.NoError(t, WriteSubmitResponse(&buffer, expected))
|
|
require.Equal(t, dataHeaderSize, buffer.Len())
|
|
|
|
header, err := ReadDataHeader(&buffer)
|
|
require.NoError(t, err)
|
|
actual, err := ReadSubmitResponseBody(&buffer, header, expected.Header.Direction)
|
|
require.NoError(t, err)
|
|
require.Equal(t, DataHeader{Command: RetSubmit, SeqNum: expected.Header.SeqNum}, actual.Header)
|
|
require.Equal(t, expected.ActualLength, actual.ActualLength)
|
|
require.Equal(t, expected.NumberOfPackets, actual.NumberOfPackets)
|
|
require.Empty(t, actual.Buffer)
|
|
}
|
|
|
|
func TestUSBIPSubmitResponseReadsPayloadFromOriginalDirection(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
expected := SubmitResponse{
|
|
Header: DataHeader{
|
|
Command: RetSubmit,
|
|
SeqNum: 42,
|
|
Direction: USBIPDirIn,
|
|
},
|
|
Status: 0,
|
|
ActualLength: 3,
|
|
NumberOfPackets: nonIsoPacketCount,
|
|
Buffer: []byte{4, 5, 6},
|
|
}
|
|
|
|
var buffer bytes.Buffer
|
|
require.NoError(t, WriteSubmitResponse(&buffer, expected))
|
|
|
|
header, err := ReadDataHeader(&buffer)
|
|
require.NoError(t, err)
|
|
require.Equal(t, DataHeader{Command: RetSubmit, SeqNum: expected.Header.SeqNum}, header)
|
|
|
|
actual, err := ReadSubmitResponseBody(&buffer, header, USBIPDirIn)
|
|
require.NoError(t, err)
|
|
expected.Header = header
|
|
require.Equal(t, expected, actual)
|
|
}
|
|
|
|
func TestUSBIPSubmitCommandAcceptsNonISOPacketSentinel(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var raw [28]byte
|
|
binary.BigEndian.PutUint32(raw[12:16], 0xffffffff)
|
|
command, err := ReadSubmitCommandBody(bytes.NewReader(raw[:]), DataHeader{Command: CmdSubmit, Direction: USBIPDirIn})
|
|
require.NoError(t, err)
|
|
require.Equal(t, int32(nonIsoPacketCount), command.NumberOfPackets)
|
|
require.Empty(t, command.IsoPackets)
|
|
}
|
|
|
|
func TestUSBIPUnlinkRoundTrip(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
command := UnlinkCommand{
|
|
Header: DataHeader{
|
|
Command: CmdUnlink,
|
|
SeqNum: 12,
|
|
DevID: 0x00030009,
|
|
Direction: USBIPDirOut,
|
|
Endpoint: 0,
|
|
},
|
|
SeqNum: 11,
|
|
}
|
|
|
|
var buffer bytes.Buffer
|
|
require.NoError(t, WriteUnlinkCommand(&buffer, command))
|
|
|
|
header, err := ReadDataHeader(&buffer)
|
|
require.NoError(t, err)
|
|
actualCommand, err := ReadUnlinkCommandBody(&buffer, header)
|
|
require.NoError(t, err)
|
|
require.Equal(t, command, actualCommand)
|
|
|
|
response := UnlinkResponse{
|
|
Header: DataHeader{
|
|
Command: RetUnlink,
|
|
SeqNum: command.Header.SeqNum,
|
|
DevID: command.Header.DevID,
|
|
Direction: command.Header.Direction,
|
|
Endpoint: command.Header.Endpoint,
|
|
},
|
|
Status: 0,
|
|
}
|
|
buffer.Reset()
|
|
require.NoError(t, WriteUnlinkResponse(&buffer, response))
|
|
|
|
header, err = ReadDataHeader(&buffer)
|
|
require.NoError(t, err)
|
|
actualResponse, err := ReadUnlinkResponseBody(&buffer, header)
|
|
require.NoError(t, err)
|
|
response.Header = DataHeader{Command: RetUnlink, SeqNum: command.Header.SeqNum}
|
|
require.Equal(t, response, actualResponse)
|
|
}
|
|
|
|
func TestUSBIPUnlinkDelayedFakeTransfer(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
client, server := net.Pipe()
|
|
defer client.Close()
|
|
defer server.Close()
|
|
deadline := time.Now().Add(5 * time.Second)
|
|
require.NoError(t, client.SetDeadline(deadline))
|
|
require.NoError(t, server.SetDeadline(deadline))
|
|
|
|
serverDone := make(chan error, 1)
|
|
go func() {
|
|
header, err := ReadDataHeader(server)
|
|
if err != nil {
|
|
serverDone <- err
|
|
return
|
|
}
|
|
command, err := ReadSubmitCommandBody(server, header)
|
|
if err != nil {
|
|
serverDone <- err
|
|
return
|
|
}
|
|
|
|
header, err = ReadDataHeader(server)
|
|
if err != nil {
|
|
serverDone <- err
|
|
return
|
|
}
|
|
unlink, err := ReadUnlinkCommandBody(server, header)
|
|
if err != nil {
|
|
serverDone <- err
|
|
return
|
|
}
|
|
if unlink.SeqNum != command.Header.SeqNum {
|
|
serverDone <- errors.New("unexpected unlink seq")
|
|
return
|
|
}
|
|
serverDone <- WriteUnlinkResponse(server, UnlinkResponse{
|
|
Header: DataHeader{
|
|
Command: RetUnlink,
|
|
SeqNum: unlink.Header.SeqNum,
|
|
DevID: unlink.Header.DevID,
|
|
Direction: unlink.Header.Direction,
|
|
Endpoint: unlink.Header.Endpoint,
|
|
},
|
|
Status: usbipStatusECONNRESET,
|
|
})
|
|
}()
|
|
|
|
require.NoError(t, WriteSubmitCommand(client, SubmitCommand{
|
|
Header: DataHeader{
|
|
Command: CmdSubmit,
|
|
SeqNum: 31,
|
|
DevID: 0x00030009,
|
|
Direction: USBIPDirIn,
|
|
Endpoint: 1,
|
|
},
|
|
TransferBufferLength: 64,
|
|
}))
|
|
require.NoError(t, WriteUnlinkCommand(client, UnlinkCommand{
|
|
Header: DataHeader{
|
|
Command: CmdUnlink,
|
|
SeqNum: 32,
|
|
DevID: 0x00030009,
|
|
Direction: USBIPDirIn,
|
|
Endpoint: 1,
|
|
},
|
|
SeqNum: 31,
|
|
}))
|
|
|
|
header, err := ReadDataHeader(client)
|
|
require.NoError(t, err)
|
|
require.Equal(t, RetUnlink, header.Command)
|
|
response, err := ReadUnlinkResponseBody(client, header)
|
|
require.NoError(t, err)
|
|
require.Equal(t, int32(usbipStatusECONNRESET), response.Status)
|
|
require.NoError(t, <-serverDone)
|
|
}
|
|
|
|
func TestUSBIPRejectsInvalidDataPlaneLengths(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var buffer bytes.Buffer
|
|
err := WriteSubmitCommand(&buffer, SubmitCommand{
|
|
Header: DataHeader{Command: CmdSubmit, Direction: USBIPDirOut},
|
|
TransferBufferLength: -1,
|
|
})
|
|
require.ErrorContains(t, err, "negative")
|
|
|
|
err = WriteSubmitResponse(&buffer, SubmitResponse{
|
|
Header: DataHeader{Command: RetSubmit, Direction: USBIPDirIn},
|
|
ActualLength: maxUSBIPTransferBufferLength + 1,
|
|
})
|
|
require.ErrorContains(t, err, "too large")
|
|
|
|
err = WriteSubmitCommand(&buffer, SubmitCommand{
|
|
Header: DataHeader{Command: CmdSubmit, Direction: USBIPDirOut},
|
|
TransferBufferLength: 4,
|
|
Buffer: []byte("abc"),
|
|
})
|
|
require.ErrorContains(t, err, "payload length mismatch")
|
|
|
|
err = WriteSubmitResponse(&buffer, SubmitResponse{
|
|
Header: DataHeader{Command: RetSubmit, Direction: USBIPDirIn},
|
|
ActualLength: 4,
|
|
Buffer: []byte("abc"),
|
|
})
|
|
require.ErrorContains(t, err, "payload length mismatch")
|
|
|
|
err = WriteSubmitCommand(&buffer, SubmitCommand{
|
|
Header: DataHeader{Command: CmdSubmit, Direction: USBIPDirIn},
|
|
TransferBufferLength: 4,
|
|
Buffer: []byte("abcd"),
|
|
})
|
|
require.ErrorContains(t, err, "unexpected payload buffer")
|
|
|
|
err = WriteSubmitResponse(&buffer, SubmitResponse{
|
|
Header: DataHeader{Command: RetSubmit, Direction: USBIPDirOut},
|
|
Buffer: []byte("abcd"),
|
|
})
|
|
require.ErrorContains(t, err, "unexpected payload buffer")
|
|
|
|
var raw [28]byte
|
|
binary.BigEndian.PutUint32(raw[4:8], 0xffffffff)
|
|
_, err = ReadSubmitCommandBody(bytes.NewReader(raw[:]), DataHeader{Command: CmdSubmit, Direction: USBIPDirOut})
|
|
require.ErrorContains(t, err, "negative")
|
|
|
|
raw = [28]byte{}
|
|
binary.BigEndian.PutUint32(raw[12:16], uint32(maxUSBIPIsoPackets+1))
|
|
_, err = ReadSubmitCommandBody(bytes.NewReader(raw[:]), DataHeader{Command: CmdSubmit, Direction: USBIPDirIn})
|
|
require.ErrorContains(t, err, "too large")
|
|
|
|
raw = [28]byte{}
|
|
binary.BigEndian.PutUint32(raw[12:16], 0xfffffffe)
|
|
_, err = ReadSubmitCommandBody(bytes.NewReader(raw[:]), DataHeader{Command: CmdSubmit, Direction: USBIPDirIn})
|
|
require.ErrorContains(t, err, "negative")
|
|
}
|