Skip to content

Commit

Permalink
fix(internal): invalid PCP range
Browse files Browse the repository at this point in the history
  • Loading branch information
0x9ef committed Mar 14, 2024
1 parent c94df86 commit 788b599
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 68 deletions.
8 changes: 4 additions & 4 deletions address.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

var BroadcastAddr = HardwareAddr{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
var UnsetupedAddr = HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
var EmptyAddr = HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}

// A media access control address (MAC address) is a unique identifier assigned
// to a network interface controller (NIC) for use as a network address in communications
Expand Down Expand Up @@ -51,20 +51,20 @@ func (h HardwareAddr) Oui() [3]byte { return [3]byte{h[0], h[1], h[2]} }
// Network Interface Controller
func (h HardwareAddr) Nic() [3]byte { return [3]byte{h[3], h[4], h[5]} }

// String stringify hexadecimal MAC address to output string.
// String stringifies hexadecimal MAC address to output string.
// You have to manually check if the mac address is correct
func (h HardwareAddr) String() string {
return fmt.Sprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
h[0], h[1], h[2], h[3], h[4], h[5],
)
}

// Compare comparing two MAC address for equality
// Compare compares two MAC addresses for equality
func (h HardwareAddr) Compare(raddr HardwareAddr) bool {
return bytes.Compare(h[:], raddr[:]) == 0
}

// IsEmpty returns true if MAC address have only zeroes
func (h HardwareAddr) IsEmpty() bool {
return h == HardwareAddr{0, 0, 0, 0, 0, 0}
return h == EmptyAddr
}
2 changes: 1 addition & 1 deletion ethertype.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ package ethernet
type EtherType uint16

const (
EtypeTypeIpv4 EtherType = 0x8000
EtherTypeIPv4 EtherType = 0x8000
EtherTypeIPv6 EtherType = 0x86DD
EtherTypeVlan EtherType = 0x8100
)
73 changes: 38 additions & 35 deletions frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package ethernet

import (
"encoding/binary"
"fmt"
"hash/crc32"
"io"
"sync"
Expand All @@ -20,27 +19,35 @@ import (
// other protocols (for example, Internet Protocol) carried in the frame.
// The frame ends with a frame check sequence (FCS), which is a 32-bit cyclic redundancy check
// used to detect any in-transit corruption of data.
//
// Preamble and SFD don't count into size of Ethernet frame size, because the physical layer
// determines where the frame starts.
type Frame struct {
dst HardwareAddr // destination MAC address
src HardwareAddr // source MAC address
tag8021q *Tag8021q // 802.1Q (can be nil)
tag8021q *Tag8021Q // 802.1Q (can be nil)
etherType EtherType
payload []byte
fcs [4]byte
}

const minSize = 64
// minHeaderSize is 6 bytes DST + 6 bytes SRC + 4 bytes FCS
const minHeaderSize = 18
const minPayloadSize = 46

// The maximum frame size is 1518 bytes, 18 bytes of which are overhead (header and frame check sequence),
// resulting in an MTU of 1500 bytes.
const MaxFrameSize = 1518
const (
// The minimal frame size is 64 bytes, comprising an 18-byte header and a payload of 46 bytes.
MinFrameSize = 64
MinFrameSizeWithoutFCS = 60
// The maximum frame size is 1518 bytes, 18 bytes of which are overhead (header and frame check sequence),
// resulting in an MTU of 1500 bytes.
MaxFrameSize = 1518
)

// NewFrame return constructed ethernet frame with basic source, destination MAC address
// and payload which this frame contains. If payload have lengh which less than minPayloadSize
// we fills remaining bytes with zeroes
func NewFrame(src HardwareAddr, dst HardwareAddr, payload []byte) *Frame {
func NewFrame(src HardwareAddr, dst HardwareAddr, etherType EtherType, payload []byte) *Frame {
var b []byte
pSz := len(payload)
if pSz < minPayloadSize {
Expand All @@ -54,7 +61,7 @@ func NewFrame(src HardwareAddr, dst HardwareAddr, payload []byte) *Frame {
dst: dst,
src: src,
tag8021q: nil,
etherType: 0x0800,
etherType: etherType,
payload: b,
}
return f
Expand All @@ -78,14 +85,14 @@ func (f *Frame) EtherType() EtherType { return f.etherType }
// Non-standard jumbo frames allow for larger maximum payload size.
func (f *Frame) Payload() []byte { return f.payload }

// Tag8021q IEEE 802.1Q, often referred to as Dot1q, is the networking standard that
// Tag8021Q IEEE 802.1Q, often referred to as Dot1q, is the networking standard that
// supports virtual LANs (VLANs) on an IEEE 802.3 Ethernet network.
// The standard defines a system of VLAN tagging for Ethernet frames and the accompanying
// procedures to be used by bridges and switches in handling such frames.
// The standard also contains provisions for a quality-of-service (QOS) prioritization scheme commonly
// known as IEEE 802.1p and defines the Generic Attribute Registration Protocol.
func (f *Frame) Tag8021q() *Tag8021q { return f.tag8021q }
func (f *Frame) SetTag8021q(tag *Tag8021q) { f.tag8021q = tag }
func (f *Frame) Tag8021Q() *Tag8021Q { return f.tag8021q }
func (f *Frame) SetTag8021Q(tag *Tag8021Q) { f.tag8021q = tag }

// Frame Check Sequence (FCS) refers to the extra bits and characters added to
// data packets for error detection and control.
Expand All @@ -105,13 +112,11 @@ func (f *Frame) Size() int {

var framePool = &sync.Pool{
New: func() interface{} {
// The maximum frame size is 1518 bytes, 18 bytes of which are overhead (header and frame check sequence),
// resulting in an MTU of 1500 bytes.
return make([]byte, MaxFrameSize)
},
}

func (f *Frame) marshal(fcs bool) []byte {
func (f *Frame) marshal() []byte {
b := framePool.Get().([]byte)
defer framePool.Put(b)

Expand All @@ -120,44 +125,42 @@ func (f *Frame) marshal(fcs bool) []byte {
b = append(b, f.src[:]...)
if f.tag8021q != nil {
b = append(b,
byte(f.tag8021q.Tpid>>8),
byte(f.tag8021q.Tpid),
byte(f.tag8021q.TPID>>8),
byte(f.tag8021q.TPID),
)
b = append(b,
byte(f.tag8021q.Tci>>8),
byte(f.tag8021q.Tci),
byte(f.tag8021q.TCI>>8),
byte(f.tag8021q.TCI),
)
}
b = append(b,
byte(f.etherType>>8),
byte(f.etherType),
)
b = append(b, f.payload...)
fmt.Println(len(b))
if fcs {
sum := crc32.ChecksumIEEE(b[:])
f.fcs = [4]byte{
byte(sum >> 24),
byte(sum >> 16),
byte(sum >> 8), byte(sum),
}
b = append(b, f.fcs[:]...)

sum := crc32.ChecksumIEEE(b[:])
f.fcs = [4]byte{
byte(sum >> 24),
byte(sum >> 16),
byte(sum >> 8), byte(sum),
}
b = append(b, f.fcs[:]...)
return b
}

// Marshal implements serialization to the byte representation
// of the Frame structure. If the structure contains tag8021q, performs
// additional serialization of the 802.1Q header within Frame
// Marshal serializes frame into the byte representation.
// If the structure contains 802.1Q tag, performs an additional
// encoding of the 802.1Q header within the frame.
func (f *Frame) Marshal() []byte {
return f.marshal(true)
return f.marshal()
}

// Unmarshal unmarshaling a sequence of bytes into a Frame structure representation.
// If array size is less than minSize (64) returns error io.ErrUnexpectedEOF
func Unmarshal(b []byte, f *Frame) error {
sz := len(b)
if sz < minSize {
if sz < MinFrameSizeWithoutFCS {
return io.ErrUnexpectedEOF
}

Expand All @@ -169,9 +172,9 @@ func Unmarshal(b []byte, f *Frame) error {
etype := EtherType(binary.BigEndian.Uint16(b[n : n+2]))
if etype == EtherTypeVlan {
// have a 802.1Q tag
f.tag8021q = new(Tag8021q)
f.tag8021q.Tpid = uint16(etype)
f.tag8021q.Tci = binary.BigEndian.Uint16(b[n+2 : n+4])
f.tag8021q = new(Tag8021Q)
f.tag8021q.TPID = uint16(etype)
f.tag8021q.TCI = binary.BigEndian.Uint16(b[n+2 : n+4])
f.etherType = EtherType(binary.BigEndian.Uint16(b[n+4 : n+6]))
n += 6
} else {
Expand Down
2 changes: 1 addition & 1 deletion frame80211_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestFrame80211Marshal(t *testing.T) {
qos uint16
ht uint32
sc uint16
tag8021q *Tag8021q
tag8021q *Tag8021Q
payload []byte
wantLen int
}
Expand Down
22 changes: 10 additions & 12 deletions frame_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package ethernet

import (
"fmt"
"math/rand"
"testing"
"time"
Expand All @@ -14,14 +13,14 @@ func TestFrameMarshal(t *testing.T) {
name string
src HardwareAddr
dst HardwareAddr
tag8021q *Tag8021q
tag8021q *Tag8021Q
payload []byte
wantLen int
}

testCases := []suite{
{
name: "positive_minimum",
name: "positive_min_padding",
src: HardwareAddr{127, 127, 127, 50, 50, 50},
dst: HardwareAddr{255, 255, 255, 50, 50, 50},
payload: []byte("HELLO"),
Expand All @@ -31,9 +30,9 @@ func TestFrameMarshal(t *testing.T) {
name: "positive_tag8021q",
src: HardwareAddr{127, 127, 127, 50, 50, 50},
dst: HardwareAddr{255, 255, 255, 50, 50, 50},
tag8021q: &Tag8021q{
Tpid: 0x15,
Tci: 0x55,
tag8021q: &Tag8021Q{
TPID: 0x15,
TCI: 0x55,
},
payload: []byte("HELLO"),
wantLen: 68,
Expand All @@ -42,12 +41,11 @@ func TestFrameMarshal(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
f := NewFrame(tc.src, tc.dst, tc.payload)
f := NewFrame(tc.src, tc.dst, EtherTypeIPv4, tc.payload)
if tc.tag8021q != nil {
f.SetTag8021q(tc.tag8021q)
f.SetTag8021Q(tc.tag8021q)
}
b := f.Marshal()
fmt.Println(b)
assert.NotEmpty(t, b)
assert.Len(t, b, tc.wantLen)
})
Expand All @@ -64,7 +62,7 @@ func generatePayload() []byte {
func BenchmarkFrameMarshal(b *testing.B) {
payload := generatePayload()
b.ResetTimer()
f := NewFrame(HardwareAddr{127, 127, 127, 50, 50, 50}, HardwareAddr{255, 255, 255, 50, 50, 50}, payload)
f := NewFrame(HardwareAddr{127, 127, 127, 50, 50, 50}, HardwareAddr{255, 255, 255, 50, 50, 50}, EtherTypeIPv4, payload)
for i := 0; i < b.N; i++ {
_ = f.Marshal()
}
Expand All @@ -80,7 +78,7 @@ func TestFrameUnmarshal(t *testing.T) {

testCases := []suite{
{
name: "positive_minimum_fcs",
name: "positive_min_fcs",
data: []byte{127, 127, 127, 50, 50, 50, 255, 255, 255, 50, 50, 50, 8, 0, 72, 69, 76, 76, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 123, 123, 123},
wantSource: HardwareAddr{255, 255, 255, 50, 50, 50},
wantDestination: HardwareAddr{127, 127, 127, 50, 50, 50},
Expand All @@ -107,7 +105,7 @@ func TestFrameUnmarshal(t *testing.T) {

func BenchmarkFrameUnmarshal(b *testing.B) {
payload := generatePayload()
data := NewFrame(HardwareAddr{127, 127, 127, 50, 50, 50}, HardwareAddr{255, 255, 255, 50, 50, 50}, payload).Marshal()
data := NewFrame(HardwareAddr{127, 127, 127, 50, 50, 50}, HardwareAddr{255, 255, 255, 50, 50, 50}, EtherTypeIPv4, payload).Marshal()
for i := 0; i < b.N; i++ {
var f Frame
err := Unmarshal(data, &f)
Expand Down
16 changes: 8 additions & 8 deletions ieee8021p.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
package ethernet

const (
PcpBE = iota // Best Effort
PcpBK // Background
PcpEE // Excellent Effort
PcpCA // Critical Applications
PcpVI // Video, < 100 ms latency and jitter
PcpVO // Voice, < 10 ms latency and jitter
PcpIC // Internetwork Control
PCpNC // Network Control (highest)
PcpBE = iota + 1 // Best Effort
PcpBK // Background
PcpEE // Excellent Effort
PcpCA // Critical Applications
PcpVI // Video, < 100 ms latency and jitter
PcpVO // Voice, < 10 ms latency and jitter
PcpIC // Internetwork Control
PCpNC // Network Control (highest)
)
14 changes: 7 additions & 7 deletions ieee8021q.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@
// that can be found in the LICENSE file.
package ethernet

type Tag8021q struct {
Tpid uint16
Tci uint16
type Tag8021Q struct {
TPID uint16
TCI uint16
}

const maxPcp = 7 // from 0-7
const maxDei = 1 // from 0-1
const maxVlan = 4095 // from 0-4095

// EncodeTag8021q encodes the 3 values PCP, DEI, VLAN using bitwise operations into 1 resulting value
func Encode8021qTci(pcp uint16, dei uint16, vlan uint16) uint16 {
// Encode8021qTCI encodes PCP, DEI, VLAN using bitwise operations.
func Encode8021qTCI(pcp uint16, dei uint16, vlan uint16) uint16 {
return (vlan << 4) | (dei << 3) | pcp
}

// DecodeTag8021q decodes the resulting encoded value to 3 universal values PCP, DEI, VLAN
func Decode8021qTci(encoded uint16) (pcp uint16, dei uint16, vlan uint16) {
// Decode8021qTCI decodes encoded TCI to 3 universal values PCP, DEI, VLAN
func Decode8021qTCI(encoded uint16) (pcp uint16, dei uint16, vlan uint16) {
return encoded & maxPcp, (encoded >> 3) & maxDei, (encoded >> 4) & maxVlan
}

0 comments on commit 788b599

Please sign in to comment.