Files
cabletest/frame.go
T

159 lines
3.1 KiB
Go

package main
import (
"encoding/binary"
"fmt"
"hash/crc32"
"math/rand/v2"
)
const (
etherBase = 0x88b5
ethHdrLen = 14
hdrLen = 24
hdrMagic = 0x43424c54
minFrame = ethHdrLen + hdrLen
maxFrame = 9216
)
var crcTable = crc32.MakeTable(crc32.Castagnoli)
type pattern struct {
name string
fill func([]byte)
}
var patterns = []pattern{
{"zeros", func(b []byte) { clear(b) }},
{"ones", func(b []byte) {
for i := range b {
b[i] = 0xff
}
}},
{"alt", func(b []byte) {
for i := range b {
if i%2 == 0 {
b[i] = 0x55
} else {
b[i] = 0xaa
}
}
}},
{"incr", func(b []byte) {
for i := range b {
b[i] = byte(i)
}
}},
{"prbs", func(b []byte) {
s := uint64(0x0123456789abcdef)
for i := range b {
s ^= s << 13
s ^= s >> 7
s ^= s << 17
b[i] = byte(s)
}
}},
{"random", func(b []byte) {
r := rand.New(rand.NewPCG(0xc0ffee, 0x5eed))
for i := range b {
b[i] = byte(r.Uint32())
}
}},
}
func patternIndex(name string) (int, error) {
for i, p := range patterns {
if p.name == name {
return i, nil
}
}
names := make([]string, len(patterns))
for i, p := range patterns {
names[i] = p.name
}
return 0, fmt.Errorf("unknown pattern %q (have %v)", name, names)
}
type frameSpec struct {
patIdx int
ref []byte
crcFor map[int]uint32
dstMAC [6]byte
srcMAC [6]byte
etherType uint16
sizes []int
maxSize int
}
func newFrameSpec(patIdx int, dst, src [6]byte, etherType uint16, sizes []int) *frameSpec {
maxSize := 0
for _, s := range sizes {
if s > maxSize {
maxSize = s
}
}
ref := make([]byte, maxSize-minFrame)
patterns[patIdx].fill(ref)
crcFor := make(map[int]uint32, len(sizes))
for _, s := range sizes {
crcFor[s] = crc32.Checksum(ref[:s-minFrame], crcTable)
}
return &frameSpec{
patIdx: patIdx,
ref: ref,
crcFor: crcFor,
dstMAC: dst,
srcMAC: src,
etherType: etherType,
sizes: sizes,
maxSize: maxSize,
}
}
func (f *frameSpec) prefill(buf []byte) {
copy(buf[0:6], f.dstMAC[:])
copy(buf[6:12], f.srcMAC[:])
binary.BigEndian.PutUint16(buf[12:14], f.etherType)
copy(buf[minFrame:], f.ref)
}
func putHeader(buf []byte, patIdx int, stream uint16, seq uint64, payLen int, crc uint32) {
h := buf[ethHdrLen:]
binary.BigEndian.PutUint32(h[0:4], hdrMagic)
h[4] = 1
h[5] = byte(patIdx)
binary.BigEndian.PutUint16(h[6:8], stream)
binary.BigEndian.PutUint64(h[8:16], seq)
binary.BigEndian.PutUint16(h[16:18], uint16(payLen))
binary.BigEndian.PutUint16(h[18:20], 0)
binary.BigEndian.PutUint32(h[20:24], crc)
}
type parsed struct {
patIdx int
stream uint16
seq uint64
payLen int
crc uint32
}
func parseHeader(buf []byte) (parsed, bool) {
var p parsed
if len(buf) < minFrame {
return p, false
}
h := buf[ethHdrLen:]
if binary.BigEndian.Uint32(h[0:4]) != hdrMagic {
return p, false
}
p.patIdx = int(h[5])
p.stream = binary.BigEndian.Uint16(h[6:8])
p.seq = binary.BigEndian.Uint64(h[8:16])
p.payLen = int(binary.BigEndian.Uint16(h[16:18]))
p.crc = binary.BigEndian.Uint32(h[20:24])
if minFrame+p.payLen > len(buf) {
return p, false
}
return p, true
}