package usbip import ( "encoding/binary" "fmt" "log" ) // urbHeaderSize is the fixed 20-byte USB/IP basic header. const urbHeaderSize = 20 // urbMessageSize is the basic header plus the 28-byte command/return body. const urbMessageSize = 48 // TraceRequest logs a CMD_SUBMIT or CMD_UNLINK frame travelling from the use // side towards the share side. Callers must gate this on protocol.Debug. func TraceRequest(tag string, data []byte) { if len(data) < urbHeaderSize { return } cmd := binary.BigEndian.Uint32(data[0:4]) seqNum := binary.BigEndian.Uint32(data[4:8]) dir := binary.BigEndian.Uint32(data[12:16]) ep := binary.BigEndian.Uint32(data[16:20]) switch cmd { case CmdSubmit: var extra string if ep == 0 && len(data) >= urbMessageSize { // The 8-byte setup packet sits at the end of the command body. setup := data[urbMessageSize-8 : urbMessageSize] extra = fmt.Sprintf(" setup=0x%02x/0x%02x wVal=0x%04x wIdx=0x%04x wLen=%d", setup[0], setup[1], binary.LittleEndian.Uint16(setup[2:4]), binary.LittleEndian.Uint16(setup[4:6]), binary.LittleEndian.Uint16(setup[6:8])) } log.Printf("[%s] -> CMD_SUBMIT seq=%d EP%d %s%s (%d bytes)", tag, seqNum, ep, dirName(dir), extra, len(data)) case CmdUnlink: log.Printf("[%s] -> CMD_UNLINK seq=%d (%d bytes)", tag, seqNum, len(data)) } } // TraceResponse logs a RET_SUBMIT or RET_UNLINK frame travelling from the // share side back to the use side. Callers must gate this on protocol.Debug. func TraceResponse(tag string, data []byte) { if len(data) < urbMessageSize { return } cmd := binary.BigEndian.Uint32(data[0:4]) seqNum := binary.BigEndian.Uint32(data[4:8]) dir := binary.BigEndian.Uint32(data[12:16]) ep := binary.BigEndian.Uint32(data[16:20]) status := int32(binary.BigEndian.Uint32(data[20:24])) switch cmd { case RetSubmit: actualLen := binary.BigEndian.Uint32(data[24:28]) var payload string if dir == DirIn && actualLen > 0 && len(data) > urbMessageSize { end := urbMessageSize + int(actualLen) if end > len(data) { end = len(data) } if end-urbMessageSize > 16 { end = urbMessageSize + 16 } payload = fmt.Sprintf(" data=%x", data[urbMessageSize:end]) } log.Printf("[%s] <- RET_SUBMIT seq=%d EP%d %s status=%d actual=%d%s", tag, seqNum, ep, dirName(dir), status, actualLen, payload) case RetUnlink: log.Printf("[%s] <- RET_UNLINK seq=%d status=%d", tag, seqNum, status) } } func dirName(dir uint32) string { if dir == DirIn { return "IN" } return "OUT" }