Ethernet frame (layer 2, IEEE 802.3): Go parsing library

Ethernet frame is a OSI data link layer (layer 2) protocol data unit for Ethernet networks. In practice, many other networks and/or in-file dumps adopted the same format for encapsulation purposes.

KS implementation details

License: CC0-1.0
Minimal Kaitai Struct required: 0.8

References

This page hosts a formal specification of Ethernet frame (layer 2, IEEE 802.3) using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Go source code to parse Ethernet frame (layer 2, IEEE 802.3)

ethernet_frame.go

// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.

import (
	"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
	"bytes"
)


/**
 * Ethernet frame is a OSI data link layer (layer 2) protocol data unit
 * for Ethernet networks. In practice, many other networks and/or
 * in-file dumps adopted the same format for encapsulation purposes.
 * @see <a href="https://ieeexplore.ieee.org/document/7428776">Source</a>
 */

type EthernetFrame_EtherTypeEnum int
const (
	EthernetFrame_EtherTypeEnum__Ipv4 EthernetFrame_EtherTypeEnum = 2048
	EthernetFrame_EtherTypeEnum__X75Internet EthernetFrame_EtherTypeEnum = 2049
	EthernetFrame_EtherTypeEnum__NbsInternet EthernetFrame_EtherTypeEnum = 2050
	EthernetFrame_EtherTypeEnum__EcmaInternet EthernetFrame_EtherTypeEnum = 2051
	EthernetFrame_EtherTypeEnum__Chaosnet EthernetFrame_EtherTypeEnum = 2052
	EthernetFrame_EtherTypeEnum__X25Level3 EthernetFrame_EtherTypeEnum = 2053
	EthernetFrame_EtherTypeEnum__Arp EthernetFrame_EtherTypeEnum = 2054
	EthernetFrame_EtherTypeEnum__Ieee8021qTpid EthernetFrame_EtherTypeEnum = 33024
	EthernetFrame_EtherTypeEnum__Ipv6 EthernetFrame_EtherTypeEnum = 34525
)
type EthernetFrame struct {
	DstMac []byte
	SrcMac []byte
	EtherType1 EthernetFrame_EtherTypeEnum
	Tci *EthernetFrame_TagControlInfo
	EtherType2 EthernetFrame_EtherTypeEnum
	Body interface{}
	_io *kaitai.Stream
	_root *EthernetFrame
	_parent interface{}
	_raw_Body []byte
	_f_etherType bool
	etherType EthernetFrame_EtherTypeEnum
}
func NewEthernetFrame() *EthernetFrame {
	return &EthernetFrame{
	}
}

func (this *EthernetFrame) Read(io *kaitai.Stream, parent interface{}, root *EthernetFrame) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp1, err := this._io.ReadBytes(int(6))
	if err != nil {
		return err
	}
	tmp1 = tmp1
	this.DstMac = tmp1
	tmp2, err := this._io.ReadBytes(int(6))
	if err != nil {
		return err
	}
	tmp2 = tmp2
	this.SrcMac = tmp2
	tmp3, err := this._io.ReadU2be()
	if err != nil {
		return err
	}
	this.EtherType1 = EthernetFrame_EtherTypeEnum(tmp3)
	if (this.EtherType1 == EthernetFrame_EtherTypeEnum__Ieee8021qTpid) {
		tmp4 := NewEthernetFrame_TagControlInfo()
		err = tmp4.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Tci = tmp4
	}
	if (this.EtherType1 == EthernetFrame_EtherTypeEnum__Ieee8021qTpid) {
		tmp5, err := this._io.ReadU2be()
		if err != nil {
			return err
		}
		this.EtherType2 = EthernetFrame_EtherTypeEnum(tmp5)
	}
	tmp6, err := this.EtherType()
	if err != nil {
		return err
	}
	switch (tmp6) {
	case EthernetFrame_EtherTypeEnum__Ipv4:
		tmp7, err := this._io.ReadBytesFull()
		if err != nil {
			return err
		}
		tmp7 = tmp7
		this._raw_Body = tmp7
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp8 := NewIpv4Packet()
		err = tmp8.Read(_io__raw_Body, this, nil)
		if err != nil {
			return err
		}
		this.Body = tmp8
	case EthernetFrame_EtherTypeEnum__Ipv6:
		tmp9, err := this._io.ReadBytesFull()
		if err != nil {
			return err
		}
		tmp9 = tmp9
		this._raw_Body = tmp9
		_io__raw_Body := kaitai.NewStream(bytes.NewReader(this._raw_Body))
		tmp10 := NewIpv6Packet()
		err = tmp10.Read(_io__raw_Body, this, nil)
		if err != nil {
			return err
		}
		this.Body = tmp10
	default:
		tmp11, err := this._io.ReadBytesFull()
		if err != nil {
			return err
		}
		tmp11 = tmp11
		this._raw_Body = tmp11
	}
	return err
}

/**
 * Ether type can be specied in several places in the frame. If
 * first location bears special marker (0x8100), then it is not the
 * real ether frame yet, an additional payload (`tci`) is expected
 * and real ether type is upcoming next.
 */
func (this *EthernetFrame) EtherType() (v EthernetFrame_EtherTypeEnum, err error) {
	if (this._f_etherType) {
		return this.etherType, nil
	}
	var tmp12 EthernetFrame_EtherTypeEnum;
	if (this.EtherType1 == EthernetFrame_EtherTypeEnum__Ieee8021qTpid) {
		tmp12 = this.EtherType2
	} else {
		tmp12 = this.EtherType1
	}
	this.etherType = EthernetFrame_EtherTypeEnum(tmp12)
	this._f_etherType = true
	return this.etherType, nil
}

/**
 * Destination MAC address
 */

/**
 * Source MAC address
 */

/**
 * Either ether type or TPID if it is a IEEE 802.1Q frame
 */

/**
 * Tag Control Information (TCI) is an extension of IEEE 802.1Q to
 * support VLANs on normal IEEE 802.3 Ethernet network.
 */
type EthernetFrame_TagControlInfo struct {
	Priority uint64
	DropEligible bool
	VlanId uint64
	_io *kaitai.Stream
	_root *EthernetFrame
	_parent *EthernetFrame
}
func NewEthernetFrame_TagControlInfo() *EthernetFrame_TagControlInfo {
	return &EthernetFrame_TagControlInfo{
	}
}

func (this *EthernetFrame_TagControlInfo) Read(io *kaitai.Stream, parent *EthernetFrame, root *EthernetFrame) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp13, err := this._io.ReadBitsIntBe(3)
	if err != nil {
		return err
	}
	this.Priority = tmp13
	tmp14, err := this._io.ReadBitsIntBe(1)
	if err != nil {
		return err
	}
	this.DropEligible = tmp14 != 0
	tmp15, err := this._io.ReadBitsIntBe(12)
	if err != nil {
		return err
	}
	this.VlanId = tmp15
	return err
}

/**
 * Priority Code Point (PCP) is used to specify priority for
 * different kinds of traffic.
 */

/**
 * Drop Eligible Indicator (DEI) specifies if frame is eligible
 * to dropping while congestion is detected for certain classes
 * of traffic.
 */

/**
 * VLAN Identifier (VID) specifies which VLAN this frame
 * belongs to.
 */