io.pkts.framer.EthernetFramer Maven / Gradle / Ivy
/**
*
*/
package io.pkts.framer;
import java.io.IOException;
import java.io.OutputStream;
import io.pkts.buffer.Buffer;
import io.pkts.frame.UnknownEtherType;
import io.pkts.packet.MACPacket;
import io.pkts.packet.PCapPacket;
import io.pkts.packet.impl.MACPacketImpl;
import io.pkts.protocol.Protocol;
/**
* Simple framer for framing Ethernet frames
*
* @author [email protected]
*/
public class EthernetFramer implements Framer {
public EthernetFramer() {
}
/**
* {@inheritDoc}
*/
@Override
public Protocol getProtocol() {
return Protocol.ETHERNET_II;
}
/**
* {@inheritDoc}
*/
@Override
public MACPacket frame(final PCapPacket parent, final Buffer buffer) throws IOException, FramingException {
if (parent == null) {
throw new IllegalArgumentException("The parent frame cannot be null");
}
// final Buffer destMacAddress = buffer.readBytes(6);
// final Buffer srcMacAddress = buffer.readBytes(6);
// final byte b1 = buffer.readByte();
// final byte b2 = buffer.readByte();
if (buffer.getReadableBytes() < 14) {
throw new FramingException("not enough bytes for header", getProtocol());
}
Buffer headers;
try {
EtherType etherType = getEtherType(buffer.getByte(12), buffer.getByte(13));
if (etherType == EtherType.Dot1Q) {
getEtherType(buffer.getByte(16), buffer.getByte(17));
headers = buffer.readBytes(18);
} else {
headers = buffer.readBytes(14);
}
} catch (IndexOutOfBoundsException e) {
throw new FramingException("not enough bytes for header", getProtocol());
} catch (final UnknownEtherType e) {
throw new FramingException(String.format("unknown ether type: 0x%02x%02x", e.getB1(), e.getB2()), getProtocol());
}
final Buffer payload = buffer.slice(buffer.capacity());
return new MACPacketImpl(Protocol.ETHERNET_II, parent, headers, payload);
}
public static EtherType getEtherType(final byte b1, final byte b2) throws UnknownEtherType {
final EtherType type = getEtherTypeSafe(b1, b2);
if (type != null) {
return type;
}
// will implement as we need to
throw new UnknownEtherType(b1, b2);
}
public static EtherType getEtherTypeSafe(final byte b1, final byte b2) {
int type = ((b1 << 8) & 0xFF00) | (b2 & 0xFF);
if (type < 1536) {
return EtherType.None;
}
for (EtherType t: EtherType.values()) {
if (b1 == t.b1 && b2 == t.b2) {
return t;
}
}
return null;
}
@Override
public boolean accept(final Buffer data) {
return false;
}
public enum EtherType {
IPv4((byte) 0x08, (byte) 0x00),
ARP((byte) 0x08, (byte) 0x06),
IPv6((byte) 0x86, (byte) 0xdd),
LLDP((byte) 0x88, (byte) 0xcc),
EAPOL((byte) 0x88, (byte) 0x8e),
// Representing EtherType < 1536, which is actually a length of the frame and not a meaningful type
None((byte) 0x00, (byte) 0x00),
Dot1Q((byte) 0x81, (byte) 0x00)
;
private final byte b1;
private final byte b2;
EtherType(final byte b1, final byte b2) {
this.b1 = b1;
this.b2 = b2;
}
public byte getB1() {
return b1;
}
public byte getB2() {
return b2;
}
public void write(final OutputStream out) throws IOException {
out.write(this.b1);
out.write(this.b2);
}
}
}