Ethernet frame (layer 2, IEEE 802.3): Java 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.

Usage

Runtime library

All parsing code for Java generated by Kaitai Struct depends on the Java runtime library. You have to install it before you can parse data.

The Java runtime library is published in the Maven Central Repository. Refer to the artifact page for instructions how to add it into your project with the build tool that you use.

Code

Parse a local file and get structure in memory:

EthernetFrame data = EthernetFrame.fromFile("path/to/local/file.Ethernet frame (layer 2, IEEE 802.3)");

Or parse structure from a byte array:

byte[] someArray = new byte[] { ... };
EthernetFrame data = new EthernetFrame(new ByteBufferKaitaiStream(someArray));

After that, one can get various attributes from the structure by invoking getter methods like:

data.dstMac() // => Destination MAC address
data.etherType() // => 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.

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

EthernetFrame.java

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

import io.kaitai.struct.ByteBufferKaitaiStream;
import io.kaitai.struct.KaitaiStruct;
import io.kaitai.struct.KaitaiStream;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;


/**
 * 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>
 */
public class EthernetFrame extends KaitaiStruct {
    public static EthernetFrame fromFile(String fileName) throws IOException {
        return new EthernetFrame(new ByteBufferKaitaiStream(fileName));
    }

    public enum EtherTypeEnum {
        IPV4(2048),
        X_75_INTERNET(2049),
        NBS_INTERNET(2050),
        ECMA_INTERNET(2051),
        CHAOSNET(2052),
        X_25_LEVEL_3(2053),
        ARP(2054),
        IEEE_802_1Q_TPID(33024),
        IPV6(34525);

        private final long id;
        EtherTypeEnum(long id) { this.id = id; }
        public long id() { return id; }
        private static final Map<Long, EtherTypeEnum> byId = new HashMap<Long, EtherTypeEnum>(9);
        static {
            for (EtherTypeEnum e : EtherTypeEnum.values())
                byId.put(e.id(), e);
        }
        public static EtherTypeEnum byId(long id) { return byId.get(id); }
    }

    public EthernetFrame(KaitaiStream _io) {
        this(_io, null, null);
    }

    public EthernetFrame(KaitaiStream _io, KaitaiStruct _parent) {
        this(_io, _parent, null);
    }

    public EthernetFrame(KaitaiStream _io, KaitaiStruct _parent, EthernetFrame _root) {
        super(_io);
        this._parent = _parent;
        this._root = _root == null ? this : _root;
        _read();
    }
    private void _read() {
        this.dstMac = this._io.readBytes(6);
        this.srcMac = this._io.readBytes(6);
        this.etherType1 = EtherTypeEnum.byId(this._io.readU2be());
        if (etherType1() == EtherTypeEnum.IEEE_802_1Q_TPID) {
            this.tci = new TagControlInfo(this._io, this, _root);
        }
        if (etherType1() == EtherTypeEnum.IEEE_802_1Q_TPID) {
            this.etherType2 = EtherTypeEnum.byId(this._io.readU2be());
        }
        {
            EtherTypeEnum on = etherType();
            if (on != null) {
                switch (etherType()) {
                case IPV4: {
                    this._raw_body = this._io.readBytesFull();
                    KaitaiStream _io__raw_body = new ByteBufferKaitaiStream(_raw_body);
                    this.body = new Ipv4Packet(_io__raw_body);
                    break;
                }
                case IPV6: {
                    this._raw_body = this._io.readBytesFull();
                    KaitaiStream _io__raw_body = new ByteBufferKaitaiStream(_raw_body);
                    this.body = new Ipv6Packet(_io__raw_body);
                    break;
                }
                default: {
                    this.body = this._io.readBytesFull();
                    break;
                }
                }
            } else {
                this.body = this._io.readBytesFull();
            }
        }
    }

    /**
     * Tag Control Information (TCI) is an extension of IEEE 802.1Q to
     * support VLANs on normal IEEE 802.3 Ethernet network.
     */
    public static class TagControlInfo extends KaitaiStruct {
        public static TagControlInfo fromFile(String fileName) throws IOException {
            return new TagControlInfo(new ByteBufferKaitaiStream(fileName));
        }

        public TagControlInfo(KaitaiStream _io) {
            this(_io, null, null);
        }

        public TagControlInfo(KaitaiStream _io, EthernetFrame _parent) {
            this(_io, _parent, null);
        }

        public TagControlInfo(KaitaiStream _io, EthernetFrame _parent, EthernetFrame _root) {
            super(_io);
            this._parent = _parent;
            this._root = _root;
            _read();
        }
        private void _read() {
            this.priority = this._io.readBitsIntBe(3);
            this.dropEligible = this._io.readBitsIntBe(1) != 0;
            this.vlanId = this._io.readBitsIntBe(12);
        }
        private long priority;
        private boolean dropEligible;
        private long vlanId;
        private EthernetFrame _root;
        private EthernetFrame _parent;

        /**
         * Priority Code Point (PCP) is used to specify priority for
         * different kinds of traffic.
         */
        public long priority() { return priority; }

        /**
         * Drop Eligible Indicator (DEI) specifies if frame is eligible
         * to dropping while congestion is detected for certain classes
         * of traffic.
         */
        public boolean dropEligible() { return dropEligible; }

        /**
         * VLAN Identifier (VID) specifies which VLAN this frame
         * belongs to.
         */
        public long vlanId() { return vlanId; }
        public EthernetFrame _root() { return _root; }
        public EthernetFrame _parent() { return _parent; }
    }
    private EtherTypeEnum etherType;

    /**
     * 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.
     */
    public EtherTypeEnum etherType() {
        if (this.etherType != null)
            return this.etherType;
        this.etherType = (etherType1() == EtherTypeEnum.IEEE_802_1Q_TPID ? etherType2() : etherType1());
        return this.etherType;
    }
    private byte[] dstMac;
    private byte[] srcMac;
    private EtherTypeEnum etherType1;
    private TagControlInfo tci;
    private EtherTypeEnum etherType2;
    private Object body;
    private EthernetFrame _root;
    private KaitaiStruct _parent;
    private byte[] _raw_body;

    /**
     * Destination MAC address
     */
    public byte[] dstMac() { return dstMac; }

    /**
     * Source MAC address
     */
    public byte[] srcMac() { return srcMac; }

    /**
     * Either ether type or TPID if it is a IEEE 802.1Q frame
     */
    public EtherTypeEnum etherType1() { return etherType1; }
    public TagControlInfo tci() { return tci; }
    public EtherTypeEnum etherType2() { return etherType2; }
    public Object body() { return body; }
    public EthernetFrame _root() { return _root; }
    public KaitaiStruct _parent() { return _parent; }
    public byte[] _raw_body() { return _raw_body; }
}