mirror of
https://github.com/songgao/packets.git
synced 2025-09-26 19:11:15 +08:00
add ethernet
This commit is contained in:
50
ethernet/ethertypes.go
Normal file
50
ethernet/ethertypes.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package ethernet
|
||||
|
||||
// Ethertype is a type used represent the ethertype of an ethernet frame.
|
||||
// Defined as a 2-byte array, variables of this type are intended to be used as
|
||||
// immutable values.
|
||||
type Ethertype [2]byte
|
||||
|
||||
// Common ethertype values
|
||||
var (
|
||||
IPv4 = Ethertype{0x08, 0x00}
|
||||
ARP = Ethertype{0x08, 0x06}
|
||||
WakeOnLAN = Ethertype{0x08, 0x42}
|
||||
TRILL = Ethertype{0x22, 0xF3}
|
||||
DECnetPhase4 = Ethertype{0x60, 0x03}
|
||||
RARP = Ethertype{0x80, 0x35}
|
||||
AppleTalk = Ethertype{0x80, 0x9B}
|
||||
AARP = Ethertype{0x80, 0xF3}
|
||||
IPX1 = Ethertype{0x81, 0x37}
|
||||
IPX2 = Ethertype{0x81, 0x38}
|
||||
QNXQnet = Ethertype{0x82, 0x04}
|
||||
IPv6 = Ethertype{0x86, 0xDD}
|
||||
EthernetFlowControl = Ethertype{0x88, 0x08}
|
||||
IEEE802_3 = Ethertype{0x88, 0x09}
|
||||
CobraNet = Ethertype{0x88, 0x19}
|
||||
MPLSUnicast = Ethertype{0x88, 0x47}
|
||||
MPLSMulticast = Ethertype{0x88, 0x48}
|
||||
PPPoEDiscovery = Ethertype{0x88, 0x63}
|
||||
PPPoESession = Ethertype{0x88, 0x64}
|
||||
JumboFrames = Ethertype{0x88, 0x70}
|
||||
HomePlug1_0MME = Ethertype{0x88, 0x7B}
|
||||
IEEE802_1X = Ethertype{0x88, 0x8E}
|
||||
PROFINET = Ethertype{0x88, 0x92}
|
||||
HyperSCSI = Ethertype{0x88, 0x9A}
|
||||
AoE = Ethertype{0x88, 0xA2}
|
||||
EtherCAT = Ethertype{0x88, 0xA4}
|
||||
EthernetPowerlink = Ethertype{0x88, 0xAB}
|
||||
LLDP = Ethertype{0x88, 0xCC}
|
||||
SERCOS3 = Ethertype{0x88, 0xCD}
|
||||
WSMP = Ethertype{0x88, 0xDC}
|
||||
HomePlugAVMME = Ethertype{0x88, 0xE1}
|
||||
MRP = Ethertype{0x88, 0xE3}
|
||||
IEEE802_1AE = Ethertype{0x88, 0xE5}
|
||||
IEEE1588 = Ethertype{0x88, 0xF7}
|
||||
IEEE802_1ag = Ethertype{0x89, 0x02}
|
||||
FCoE = Ethertype{0x89, 0x06}
|
||||
FCoEInit = Ethertype{0x89, 0x14}
|
||||
RoCE = Ethertype{0x89, 0x15}
|
||||
CTP = Ethertype{0x90, 0x00}
|
||||
VeritasLLT = Ethertype{0xCA, 0xFE}
|
||||
)
|
114
ethernet/frame.go
Normal file
114
ethernet/frame.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package ethernet
|
||||
|
||||
import "net"
|
||||
|
||||
// Frame represents an ethernet frame. The length of the underlying slice of a
|
||||
// Frame should always reflect the ethernet frame length.
|
||||
type Frame []byte
|
||||
|
||||
// Tagging is a type used to indicate whether/how a frame is tagged. The value
|
||||
// is number of bytes taken by tagging.
|
||||
type Tagging byte
|
||||
|
||||
// Const values for different taggings
|
||||
const (
|
||||
NotTagged Tagging = 0
|
||||
Tagged Tagging = 4
|
||||
DoubleTagged Tagging = 8
|
||||
)
|
||||
|
||||
// Destination returns the destination address field of the frame. The address
|
||||
// references a slice on the frame.
|
||||
//
|
||||
// It is not safe to use this method if f is nil or an invalid ethernet frame.
|
||||
func (f Frame) Destination() net.HardwareAddr {
|
||||
return net.HardwareAddr(f[:6:6])
|
||||
}
|
||||
|
||||
// Source returns the source address field of the frame. The address references
|
||||
// a slice on the frame.
|
||||
//
|
||||
// It is not safe to use this method if f is nil or an invalid ethernet frame.
|
||||
func (f Frame) Source() net.HardwareAddr {
|
||||
return net.HardwareAddr(f[6:12:12])
|
||||
}
|
||||
|
||||
// Tagging returns whether/how the frame has 802.1Q tag(s).
|
||||
//
|
||||
// It is not safe to use this method if f is nil or an invalid ethernet frame.
|
||||
func (f Frame) Tagging() Tagging {
|
||||
if f[12] == 0x81 && f[13] == 0x00 {
|
||||
return Tagged
|
||||
} else if f[12] == 0x88 && f[13] == 0xa8 {
|
||||
return DoubleTagged
|
||||
}
|
||||
return NotTagged
|
||||
}
|
||||
|
||||
// Tag returns a slice holding the tag part of the frame, if any. Note taht
|
||||
// this includes the Tag Protocol Identifier (TPID), e.g. 0x8100 or 0x88a8.
|
||||
// Upper layer should use the returned slice for both reading and writing.
|
||||
//
|
||||
// It is not safe to use this method if f is nil or an invalid ethernet frame.
|
||||
func (f Frame) Tags() []byte {
|
||||
tagging := f.Tagging()
|
||||
return f[12 : 12+tagging : 12+tagging]
|
||||
}
|
||||
|
||||
// Ethertype returns the ethertype field of the frame.
|
||||
//
|
||||
// It is not safe to use this method if f is nil or an invalid ethernet frame.
|
||||
func (f Frame) Ethertype() Ethertype {
|
||||
ethertypePos := 12 + f.Tagging()
|
||||
return Ethertype{f[ethertypePos], f[ethertypePos+1]}
|
||||
}
|
||||
|
||||
// Payload returns a slice holding the payload part of the frame. Upper layer
|
||||
// should use the returned slice for both reading and writing purposes.
|
||||
//
|
||||
// It is not safe to use this method if f is nil or an invalid ethernet frame.
|
||||
func (f Frame) Payload() []byte {
|
||||
return f[12+f.Tagging()+2:]
|
||||
}
|
||||
|
||||
// Resize re-slices (*f) so that len(*f) holds exactly payloadSize bytes of
|
||||
// payload. If cap(*f) is not large enough, a new slice is made.
|
||||
//
|
||||
// If len(*f) is less than 14 bytes, it is assumed to be not tagged.
|
||||
//
|
||||
// It is safe to call Resize on a pointer to a nil Frame.
|
||||
func (f *Frame) Resize(payloadSize int) {
|
||||
tagging := NotTagged
|
||||
if len(*f) > 6+6+2 {
|
||||
tagging = f.Tagging()
|
||||
}
|
||||
f.resize(6 + 6 + int(tagging) + 2 + payloadSize)
|
||||
}
|
||||
|
||||
// Prepare prepares *f to be used, by filling in dst/src address, setting up
|
||||
// proper tagging and ethertype, and resizing it to proper length.
|
||||
//
|
||||
// It is safe to call Prepare on a pointer to a nil Frame or invalid Frame.
|
||||
func (f *Frame) Prepare(dst net.HardwareAddr, src net.HardwareAddr, tagging Tagging, ethertype Ethertype, payloadSize int) {
|
||||
f.resize(6 + 6 + int(tagging) + 2 + payloadSize)
|
||||
copy((*f)[0:6:6], dst)
|
||||
copy((*f)[6:12:12], src)
|
||||
if tagging == Tagged {
|
||||
(*f)[12] = 0x81
|
||||
(*f)[13] = 0x00
|
||||
} else if tagging == DoubleTagged {
|
||||
(*f)[12] = 0x88
|
||||
(*f)[13] = 0xa8
|
||||
}
|
||||
(*f)[12+tagging] = ethertype[0]
|
||||
(*f)[12+tagging+1] = ethertype[1]
|
||||
return
|
||||
}
|
||||
|
||||
func (f *Frame) resize(length int) {
|
||||
if cap(*f) < length {
|
||||
*f = make(Frame, length, length)
|
||||
} else {
|
||||
*f = (*f)[:length]
|
||||
}
|
||||
}
|
61
ethernet/frame_test.go
Normal file
61
ethernet/frame_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package ethernet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func panics(f func()) (didPanic bool) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
didPanic = true
|
||||
}
|
||||
}()
|
||||
f()
|
||||
return
|
||||
}
|
||||
|
||||
func mustParseMAC(str string) (addr net.HardwareAddr) {
|
||||
var err error
|
||||
addr, err = net.ParseMAC(str)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func TestPrepare(t *testing.T) {
|
||||
var frame Frame
|
||||
dst := mustParseMAC("ff:ff:ff:ff:ff:ff")
|
||||
src := mustParseMAC("12:34:56:78:9a:bc")
|
||||
(&frame).Prepare(dst, src, NotTagged, IPv6, 1024)
|
||||
if len(frame.Payload()) != 1024 {
|
||||
t.Fatalf("frame payload does not have correct length. expected %d; got %d\n", 1024, len(frame.Payload()))
|
||||
}
|
||||
expectedLength := 6 + 6 + int(NotTagged) + 2 + 1024
|
||||
if len(frame) != expectedLength {
|
||||
t.Fatalf("frame does not have correct length. expected %d; got %d\n", expectedLength, len(frame))
|
||||
}
|
||||
if !bytes.Equal([]byte(frame.Source()), []byte(src)) {
|
||||
t.Fatalf("frame source address is incorrect. expected %s; got %s\n", src.String(), frame.Source().String())
|
||||
}
|
||||
if !bytes.Equal([]byte(frame.Destination()), []byte(dst)) {
|
||||
t.Fatalf("frame destination address is incorrect. expected %s; got %s\n", dst.String(), frame.Destination().String())
|
||||
}
|
||||
if frame.Tagging() != NotTagged {
|
||||
t.Fatalf("frame tagging is incorrect. expected %d; got %d\n", NotTagged, frame.Tagging())
|
||||
}
|
||||
if frame.Ethertype() != IPv6 {
|
||||
t.Fatalf("frame ethertype is incorrect. expected %v; got %v\n", IPv6, frame.Ethertype())
|
||||
}
|
||||
}
|
||||
|
||||
func TestResize(t *testing.T) {
|
||||
var frame Frame
|
||||
(&frame).Resize(1024)
|
||||
expectedLength := 6 + 6 + int(NotTagged) + 2 + 1024
|
||||
if len(frame) != expectedLength {
|
||||
t.Fatalf("frame does not have correct length. expected %d; got %d\n", expectedLength, len(frame))
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user