-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcdc_ecm.go
141 lines (107 loc) · 3.11 KB
/
cdc_ecm.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
// Ethernet over USB driver
//
// Copyright (c) WithSecure Corporation
//
// Use of this source code is governed by the license
// that can be found in the LICENSE file.
package usbnet
import (
"encoding/binary"
"errors"
"net"
"github.com/usbarmory/tamago/soc/nxp/usb"
"gvisor.dev/gvisor/pkg/buffer"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/link/channel"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
// NIC represents an virtual Ethernet instance.
type NIC struct {
// Host MAC address
HostMAC net.HardwareAddr
// Device MAC address
DeviceMAC net.HardwareAddr
// Link is a gVisor channel endpoint
Link *channel.Endpoint
// Device is the physical interface associated to the virtual one.
Device *usb.Device
// Rx is endpoint 1 OUT function, set by Init() to ECMRx if not
// already defined.
Rx func([]byte, error) ([]byte, error)
// Tx is endpoint 1 IN function, set by Init() to ECMTx if not already
// defined.
Tx func([]byte, error) ([]byte, error)
// Control is endpoint 2 IN function, set by Init() to ECMControl if
// not already defined.
Control func([]byte, error) ([]byte, error)
maxPacketSize int
buf []byte
}
// Init initializes a virtual Ethernet instance on a specific USB device and
// configuration index.
func (eth *NIC) Init() (err error) {
if eth.Link == nil {
return errors.New("missing link endpoint")
}
if len(eth.HostMAC) != 6 || len(eth.DeviceMAC) != 6 {
return errors.New("invalid MAC address")
}
if eth.Rx == nil {
eth.Rx = eth.ECMRx
}
if eth.Tx == nil {
eth.Tx = eth.ECMTx
}
if eth.Control == nil {
eth.Control = eth.ECMControl
}
addControlInterface(eth.Device, eth)
addDataInterfaces(eth.Device, eth)
return
}
// ECMControl implements the endpoint 2 IN function.
func (eth *NIC) ECMControl(_ []byte, lastErr error) (in []byte, err error) {
// ignore for now
return
}
// ECMRx implements the endpoint 1 OUT function, used to receive Ethernet
// packet from host to device.
func (eth *NIC) ECMRx(out []byte, lastErr error) (_ []byte, err error) {
if len(eth.buf) == 0 && len(out) < 14 {
return
}
eth.buf = append(eth.buf, out...)
// more data expected or zero length packet
if len(out) == eth.maxPacketSize {
return
}
hdr := eth.buf[0:14]
proto := tcpip.NetworkProtocolNumber(binary.BigEndian.Uint16(eth.buf[12:14]))
payload := eth.buf[14:]
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
ReserveHeaderBytes: len(hdr),
Payload: buffer.MakeWithData(payload),
})
copy(pkt.LinkHeader().Push(len(hdr)), hdr)
eth.Link.InjectInbound(proto, pkt)
eth.buf = []byte{}
return
}
// ECMTx implements the endpoint 1 IN function, used to transmit Ethernet
// packet from device to host.
func (eth *NIC) ECMTx(_ []byte, lastErr error) (in []byte, err error) {
var pkt *stack.PacketBuffer
if pkt = eth.Link.Read(); pkt == nil {
return
}
proto := make([]byte, 2)
binary.BigEndian.PutUint16(proto, uint16(pkt.NetworkProtocolNumber))
// Ethernet frame header
in = append(in, eth.HostMAC...)
in = append(in, eth.DeviceMAC...)
in = append(in, proto...)
for _, v := range pkt.AsSlices() {
in = append(in, v...)
}
return
}