Browse Source

moved to imx-usbnet

master
Andrea Barisani 1 week ago
parent
commit
dc0a9b0d13
  1. 153
      soc/imx6/usb/ethernet/cdc_ecm.go
  2. 113
      soc/imx6/usb/ethernet/cdc_interface.go

153
soc/imx6/usb/ethernet/cdc_ecm.go

@ -1,153 +0,0 @@
// Ethernet over USB driver
// https://github.com/f-secure-foundry/tamago
//
// Copyright (c) F-Secure Corporation
// https://foundry.f-secure.com
//
// Use of this source code is governed by the license
// that can be found in the LICENSE file.
// Package ethernet implements a driver for Ethernet over USB emulation on
// i.MX6 SoCs.
//
// It currently implements CDC-ECM networking and for this reason the Ethernet
// device is only supported on Linux hosts. Applications are meant to use the
// driver in combination with gVisor tcpip package to expose TCP/IP networking
// stack through Ethernet over USB.
//
// This package is only meant to be used with `GOOS=tamago GOARCH=arm` as
// supported by the TamaGo framework for bare metal Go on ARM SoCs, see
// https://github.com/f-secure-foundry/tamago.
package ethernet
import (
"encoding/binary"
"errors"
"net"
"github.com/f-secure-foundry/tamago/soc/imx6/usb"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"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
Host net.HardwareAddr
// Device MAC address
Device net.HardwareAddr
// Link is a gVisor channel endpoint
Link *channel.Endpoint
// Rx is tendpoint 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 alread
// 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(device *usb.Device, configurationIndex int) (err error) {
if eth.Link == nil {
return errors.New("missing link endpoint")
}
if len(eth.Host) != 6 || len(eth.Device) != 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(device, configurationIndex, eth)
dataInterface := addDataInterface(device, configurationIndex, eth)
eth.maxPacketSize = int(dataInterface.Endpoints[0].MaxPacketSize)
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 := buffer.NewViewFromBytes(eth.buf[0:14])
proto := tcpip.NetworkProtocolNumber(binary.BigEndian.Uint16(eth.buf[12:14]))
payload := buffer.NewViewFromBytes(eth.buf[14:])
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
ReserveHeaderBytes: len(hdr),
Data: payload.ToVectorisedView(),
})
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) {
info, valid := eth.Link.Read()
if !valid {
return
}
proto := make([]byte, 2)
binary.BigEndian.PutUint16(proto, uint16(info.Proto))
// Ethernet frame header
in = append(in, eth.Host...)
in = append(in, eth.Device...)
in = append(in, proto...)
for _, v := range info.Pkt.Views() {
in = append(in, v...)
}
return
}

113
soc/imx6/usb/ethernet/cdc_interface.go

@ -1,113 +0,0 @@
// Ethernet over USB driver
// https://github.com/f-secure-foundry/tamago
//
// Copyright (c) F-Secure Corporation
// https://foundry.f-secure.com
//
// Use of this source code is governed by the license
// that can be found in the LICENSE file.
package ethernet
import (
"strings"
"github.com/f-secure-foundry/tamago/soc/imx6/usb"
)
// Build a CDC control interface.
func addControlInterface(device *usb.Device, configurationIndex int, eth *NIC) (iface *usb.InterfaceDescriptor) {
iface = &usb.InterfaceDescriptor{}
iface.SetDefaults()
iface.NumEndpoints = 1
iface.InterfaceClass = 2
iface.InterfaceSubClass = 6
iInterface, _ := device.AddString(`CDC Ethernet Control Model (ECM)`)
iface.Interface = iInterface
// Set IAD to be inserted before first interface, to support multiple
// functions in this same configuration.
iface.IAD = &usb.InterfaceAssociationDescriptor{}
iface.IAD.SetDefaults()
// alternate settings do not count
iface.IAD.InterfaceCount = 1
iface.IAD.FunctionClass = iface.InterfaceClass
iface.IAD.FunctionSubClass = iface.InterfaceSubClass
iFunction, _ := device.AddString(`CDC`)
iface.IAD.Function = iFunction
header := &usb.CDCHeaderDescriptor{}
header.SetDefaults()
iface.ClassDescriptors = append(iface.ClassDescriptors, header.Bytes())
union := &usb.CDCUnionDescriptor{}
union.SetDefaults()
// Master/Slave are identical as ECM requires the use of "alternate
// settings" for its data interface.
numInterfaces := 1 + len(device.Configurations[configurationIndex].Interfaces)
union.MasterInterface = uint8(numInterfaces - 1)
union.SlaveInterface0 = uint8(numInterfaces - 1)
iface.ClassDescriptors = append(iface.ClassDescriptors, union.Bytes())
ethernet := &usb.CDCEthernetDescriptor{}
ethernet.SetDefaults()
iMacAddress, _ := device.AddString(strings.ReplaceAll(eth.Host.String(), ":", ""))
ethernet.MacAddress = iMacAddress
iface.ClassDescriptors = append(iface.ClassDescriptors, ethernet.Bytes())
ep2IN := &usb.EndpointDescriptor{}
ep2IN.SetDefaults()
ep2IN.EndpointAddress = 0x82
ep2IN.Attributes = 3
ep2IN.MaxPacketSize = 16
ep2IN.Interval = 9
ep2IN.Function = eth.Control
iface.Endpoints = append(iface.Endpoints, ep2IN)
device.Configurations[configurationIndex].AddInterface(iface)
return
}
// Build a CDC data interface.
func addDataInterface(device *usb.Device, configurationIndex int, eth *NIC) (iface *usb.InterfaceDescriptor) {
iface = &usb.InterfaceDescriptor{}
iface.SetDefaults()
// ECM requires the use of "alternate settings" for its data interface
iface.AlternateSetting = 1
iface.NumEndpoints = 2
iface.InterfaceClass = 10
iInterface, _ := device.AddString(`CDC Data`)
iface.Interface = iInterface
ep1IN := &usb.EndpointDescriptor{}
ep1IN.SetDefaults()
ep1IN.EndpointAddress = 0x81
ep1IN.Attributes = 2
ep1IN.Function = eth.Tx
iface.Endpoints = append(iface.Endpoints, ep1IN)
ep1OUT := &usb.EndpointDescriptor{}
ep1OUT.SetDefaults()
ep1OUT.EndpointAddress = 0x01
ep1OUT.Attributes = 2
ep1OUT.Function = eth.Rx
iface.Endpoints = append(iface.Endpoints, ep1OUT)
device.Configurations[configurationIndex].AddInterface(iface)
return
}
Loading…
Cancel
Save