93 lines
1.7 KiB
Go
93 lines
1.7 KiB
Go
package vl2
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"net"
|
|
"sync"
|
|
)
|
|
|
|
const (
|
|
MinFrameSize = 14
|
|
MaxFrameSize = 65535
|
|
EtherTypeIPv4 = 0x0800
|
|
EtherTypeARP = 0x0806
|
|
EtherTypeIPv6 = 0x86DD
|
|
)
|
|
|
|
type EthernetFrame struct {
|
|
DstMAC net.HardwareAddr
|
|
SrcMAC net.HardwareAddr
|
|
EtherType uint16
|
|
Payload []byte
|
|
}
|
|
|
|
func ParseEthernetFrame(data []byte) (*EthernetFrame, error) {
|
|
if len(data) < MinFrameSize {
|
|
return nil, fmt.Errorf("frame too short: %d < %d", len(data), MinFrameSize)
|
|
}
|
|
return &EthernetFrame{
|
|
DstMAC: net.HardwareAddr(data[0:6]),
|
|
SrcMAC: net.HardwareAddr(data[6:12]),
|
|
EtherType: binary.BigEndian.Uint16(data[12:14]),
|
|
Payload: data[14:],
|
|
}, nil
|
|
}
|
|
|
|
func (f *EthernetFrame) Encode() []byte {
|
|
buf := make([]byte, MinFrameSize+len(f.Payload))
|
|
copy(buf[0:6], f.DstMAC)
|
|
copy(buf[6:12], f.SrcMAC)
|
|
binary.BigEndian.PutUint16(buf[12:14], f.EtherType)
|
|
copy(buf[14:], f.Payload)
|
|
return buf
|
|
}
|
|
|
|
func (f *EthernetFrame) IsBroadcast() bool {
|
|
for _, b := range f.DstMAC {
|
|
if b != 0xff {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (f *EthernetFrame) IsMulticast() bool {
|
|
return len(f.DstMAC) > 0 && f.DstMAC[0]&0x01 == 0x01 && !f.IsBroadcast()
|
|
}
|
|
|
|
func (f *EthernetFrame) IsARP() bool {
|
|
return f.EtherType == EtherTypeARP
|
|
}
|
|
|
|
func (f *EthernetFrame) IsIPv4() bool {
|
|
return f.EtherType == EtherTypeIPv4
|
|
}
|
|
|
|
func (f *EthernetFrame) IsIPv6() bool {
|
|
return f.EtherType == EtherTypeIPv6
|
|
}
|
|
|
|
type MACKey [6]byte
|
|
|
|
func MACToKey(mac net.HardwareAddr) MACKey {
|
|
var key MACKey
|
|
copy(key[:], mac)
|
|
return key
|
|
}
|
|
|
|
var frameBufPool = sync.Pool{
|
|
New: func() interface{} {
|
|
buf := make([]byte, MaxFrameSize)
|
|
return &buf
|
|
},
|
|
}
|
|
|
|
func GetFrameBuf() *[]byte {
|
|
return frameBufPool.Get().(*[]byte)
|
|
}
|
|
|
|
func PutFrameBuf(buf *[]byte) {
|
|
frameBufPool.Put(buf)
|
|
}
|