/* * * * Copyright 2015 AT&T Foundry * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * */ package org.onlab.packet; import java.nio.ByteBuffer; import static com.google.common.base.MoreObjects.toStringHelper; import static org.onlab.packet.PacketUtils.checkHeaderLength; import static org.onlab.packet.PacketUtils.checkInput; /** * EAPOL (Extensible Authentication Protocol over LAN) header. */ public class EAPOL extends BasePacket { private byte version = 0x01; private byte eapolType; private short packetLength; private static final int HEADER_LENGTH = 4; // EAPOL Packet Type public static final byte EAPOL_PACKET = 0x0; public static final byte EAPOL_START = 0x1; public static final byte EAPOL_LOGOFF = 0x2; public static final byte EAPOL_KEY = 0x3; public static final byte EAPOL_ASF = 0x4; public static final MacAddress PAE_GROUP_ADDR = MacAddress.valueOf(new byte[] { (byte) 0x01, (byte) 0x80, (byte) 0xc2, (byte) 0x00, (byte) 0x00, (byte) 0x03 }); /** * Gets the version. * * @return version */ public byte getVersion() { return this.version; } /** * Sets the version. * * @param version EAPOL version * @return this */ public EAPOL setVersion(final byte version) { this.version = version; return this; } /** * Gets the type. * * @return EAPOL type */ public byte getEapolType() { return this.eapolType; } /** * Sets the EAPOL type. * * @param eapolType EAPOL type * @return this */ public EAPOL setEapolType(final byte eapolType) { this.eapolType = eapolType; return this; } /** * Gets the packet length. * * @return packet length */ public short getPacketLength() { return this.packetLength; } /** * Sets the packet length. * * @param packetLen packet length * @return this */ public EAPOL setPacketLength(final short packetLen) { this.packetLength = packetLen; return this; } /** * Serializes the packet, based on the code/type using the payload * to compute its length. * * @return this */ @Override public byte[] serialize() { byte[] payloadData = null; if (this.payload != null) { this.payload.setParent(this); payloadData = this.payload.serialize(); } // prepare the buffer to hold the version (1), packet type (1), // packet length (2) and the eap payload. // if there is no payload, packet length is 0 byte[] data = new byte[4 + this.packetLength]; final ByteBuffer bb = ByteBuffer.wrap(data); bb.put(this.version); bb.put(this.eapolType); bb.putShort(this.packetLength); // put the EAP payload if (payloadData != null) { bb.put(payloadData); } return data; } @Override public int hashCode() { final int prime = 3889; int result = super.hashCode(); result = prime * result + this.version; result = prime * result + this.eapolType; result = prime * result + this.packetLength; return result; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof EAPOL)) { return false; } EAPOL that = (EAPOL) o; if (this.version != that.version) { return false; } if (this.eapolType != that.eapolType) { return false; } if (this.packetLength != that.packetLength) { return false; } return true; } /** * Deserializer for EAPOL packets. * * @return deserializer */ public static Deserializer<EAPOL> deserializer() { return (data, offset, length) -> { checkInput(data, offset, length, HEADER_LENGTH); EAPOL eapol = new EAPOL(); final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); eapol.setVersion(bb.get()); eapol.setEapolType(bb.get()); eapol.setPacketLength(bb.getShort()); if (eapol.packetLength > 0) { checkHeaderLength(length, HEADER_LENGTH + eapol.packetLength); // deserialize the EAP Payload eapol.payload = EAP.deserializer().deserialize(data, bb.position(), bb.limit() - bb.position()); eapol.payload.setParent(eapol); } return eapol; }; } @Override public IPacket deserialize(final byte[] data, final int offset, final int length) { final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); // deserialize the EAPOL header this.version = bb.get(); this.eapolType = bb.get(); this.packetLength = bb.getShort(); if (this.packetLength > 0) { // deserialize the EAP Payload this.payload = new EAP(); this.payload = this.payload.deserialize(data, bb.position(), length - 4); this.payload.setParent(this); } return this; } @Override public String toString() { return toStringHelper(getClass()) .add("version", Byte.toString(version)) .add("eapolType", Byte.toString(eapolType)) .add("packetLength", Short.toString(packetLength)) .toString(); } }