-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathethernet.go
89 lines (67 loc) · 1.69 KB
/
ethernet.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
package proto
import (
"net"
)
// EthernetFrame represents an Ethernet frame.
type EthernetFrame struct {
Destination net.HardwareAddr `json:"source"`
Source net.HardwareAddr `json:"destination"`
VlanTag uint32 `json:"vlanTag"`
EtherType uint16 `json:"etherType"`
Payload []byte `json:"payload"`
}
const minEthernetFrameSize = 6 + 6 + 4 + 2
// DecodeEthernet decodes an Ethernet frame.
func DecodeEthernet(b []byte) (EthernetFrame, error) {
frame := EthernetFrame{}
if len(b) < minEthernetFrameSize {
return frame, ErrorNotEnoughBytes
}
i := 0 // Just a helper for indexing.
// Decode MAC addresses.
frame.Destination = net.HardwareAddr(b[i : i+6])
i += 6
frame.Source = net.HardwareAddr(b[i : i+6])
i += 6
// Check for a VLAN tag.
if b[i] == 0x81 && b[i+1] == 0x00 {
i += 2
frame.VlanTag = uint32(0x81<<24) | uint32(0x00<<16) | uint32(b[i]<<8) | uint32(b[i+1])
i += 2
}
// Check the Ethernet type
if t := uint16(b[i])<<8 | uint16(b[i+1]); t >= 1536 { // If 1500 or less, it's the payload length.
frame.EtherType = t
}
i += 2
frame.Payload = b[i:]
return frame, nil
}
// Bytes returns an encoded Ethernet frame.
func (f EthernetFrame) Bytes() []byte {
i := 0
b := make([]byte, (6+6+4+2)+len(f.Payload))
copy(b, f.Destination[:])
i += 6
copy(b[i:], f.Source[:])
i += 6
if f.VlanTag != 0 {
b[i] = 0x81
b[i+1] = 0x00
i += 2
b[i] = byte(f.VlanTag >> 8)
b[i+1] = byte(f.VlanTag)
i += 2
}
if f.EtherType != 0 {
b[i] = byte(f.EtherType >> 8)
b[i+1] = byte(f.EtherType)
} else {
l := len(f.Payload)
b[i] = byte(l >> 8)
b[i+1] = byte(l)
}
i += 2
copy(b[i:], f.Payload)
return b[:i+len(f.Payload)]
}