diff options
Diffstat (limited to 'framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ARP.java')
-rw-r--r-- | framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ARP.java | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ARP.java b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ARP.java new file mode 100644 index 00000000..dc3c07f1 --- /dev/null +++ b/framework/src/onos/utils/misc/src/main/java/org/onlab/packet/ARP.java @@ -0,0 +1,439 @@ +/* + * Copyright 2014 Open Networking Laboratory + * + * 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 java.util.Arrays; + +import static org.onlab.packet.PacketUtils.*; + +/** + * + * + */ +public class ARP extends BasePacket { + public static final short HW_TYPE_ETHERNET = 0x1; + + public static final short PROTO_TYPE_IP = 0x800; + + public static final short OP_REQUEST = 0x1; + public static final short OP_REPLY = 0x2; + public static final short OP_RARP_REQUEST = 0x3; + public static final short OP_RARP_REPLY = 0x4; + + public static final short INITIAL_HEADER_LENGTH = 8; + + protected short hardwareType; + protected short protocolType; + protected byte hardwareAddressLength; + protected byte protocolAddressLength; + protected short opCode; + protected byte[] senderHardwareAddress; + protected byte[] senderProtocolAddress; + protected byte[] targetHardwareAddress; + protected byte[] targetProtocolAddress; + + /** + * @return the hardwareType + */ + public short getHardwareType() { + return this.hardwareType; + } + + /** + * @param hwType + * the hardwareType to set + * @return this + */ + public ARP setHardwareType(final short hwType) { + this.hardwareType = hwType; + return this; + } + + /** + * @return the protocolType + */ + public short getProtocolType() { + return this.protocolType; + } + + /** + * @param protoType + * the protocolType to set + * @return this + */ + public ARP setProtocolType(final short protoType) { + this.protocolType = protoType; + return this; + } + + /** + * @return the hardwareAddressLength + */ + public byte getHardwareAddressLength() { + return this.hardwareAddressLength; + } + + /** + * @param hwAddressLength + * the hardwareAddressLength to set + * @return this + */ + public ARP setHardwareAddressLength(final byte hwAddressLength) { + this.hardwareAddressLength = hwAddressLength; + return this; + } + + /** + * @return the protocolAddressLength + */ + public byte getProtocolAddressLength() { + return this.protocolAddressLength; + } + + /** + * @param protoAddressLength + * the protocolAddressLength to set + * @return this + */ + public ARP setProtocolAddressLength(final byte protoAddressLength) { + this.protocolAddressLength = protoAddressLength; + return this; + } + + /** + * @return the opCode + */ + public short getOpCode() { + return this.opCode; + } + + /** + * @param op + * the opCode to set + * @return this + */ + public ARP setOpCode(final short op) { + this.opCode = op; + return this; + } + + /** + * @return the senderHardwareAddress + */ + public byte[] getSenderHardwareAddress() { + return this.senderHardwareAddress; + } + + /** + * @param senderHWAddress + * the senderHardwareAddress to set + * @return this + */ + public ARP setSenderHardwareAddress(final byte[] senderHWAddress) { + this.senderHardwareAddress = senderHWAddress; + return this; + } + + /** + * @return the senderProtocolAddress + */ + public byte[] getSenderProtocolAddress() { + return this.senderProtocolAddress; + } + + /** + * @param senderProtoAddress + * the senderProtocolAddress to set + * @return this + */ + public ARP setSenderProtocolAddress(final byte[] senderProtoAddress) { + this.senderProtocolAddress = senderProtoAddress; + return this; + } + + public ARP setSenderProtocolAddress(final int address) { + this.senderProtocolAddress = ByteBuffer.allocate(4).putInt(address) + .array(); + return this; + } + + /** + * @return the targetHardwareAddress + */ + public byte[] getTargetHardwareAddress() { + return this.targetHardwareAddress; + } + + /** + * @param targetHWAddress + * the targetHardwareAddress to set + * @return this + */ + public ARP setTargetHardwareAddress(final byte[] targetHWAddress) { + this.targetHardwareAddress = targetHWAddress; + return this; + } + + /** + * @return the targetProtocolAddress + */ + public byte[] getTargetProtocolAddress() { + return this.targetProtocolAddress; + } + + /** + * @return True if gratuitous ARP (SPA = TPA), false otherwise + */ + public boolean isGratuitous() { + assert this.senderProtocolAddress.length == this.targetProtocolAddress.length; + + int indx = 0; + while (indx < this.senderProtocolAddress.length) { + if (this.senderProtocolAddress[indx] != this.targetProtocolAddress[indx]) { + return false; + } + indx++; + } + + return true; + } + + /** + * @param targetProtoAddress + * the targetProtocolAddress to set + * @return this + */ + public ARP setTargetProtocolAddress(final byte[] targetProtoAddress) { + this.targetProtocolAddress = targetProtoAddress; + return this; + } + + public ARP setTargetProtocolAddress(final int address) { + this.targetProtocolAddress = ByteBuffer.allocate(4).putInt(address) + .array(); + return this; + } + + @Override + public byte[] serialize() { + final int length = 8 + 2 * (0xff & this.hardwareAddressLength) + 2 + * (0xff & this.protocolAddressLength); + final byte[] data = new byte[length]; + final ByteBuffer bb = ByteBuffer.wrap(data); + bb.putShort(this.hardwareType); + bb.putShort(this.protocolType); + bb.put(this.hardwareAddressLength); + bb.put(this.protocolAddressLength); + bb.putShort(this.opCode); + bb.put(this.senderHardwareAddress, 0, 0xff & this.hardwareAddressLength); + bb.put(this.senderProtocolAddress, 0, 0xff & this.protocolAddressLength); + bb.put(this.targetHardwareAddress, 0, 0xff & this.hardwareAddressLength); + bb.put(this.targetProtocolAddress, 0, 0xff & this.protocolAddressLength); + return data; + } + + @Override + public IPacket deserialize(final byte[] data, final int offset, + final int length) { + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); + this.hardwareType = bb.getShort(); + this.protocolType = bb.getShort(); + this.hardwareAddressLength = bb.get(); + this.protocolAddressLength = bb.get(); + this.opCode = bb.getShort(); + this.senderHardwareAddress = new byte[0xff & this.hardwareAddressLength]; + bb.get(this.senderHardwareAddress, 0, this.senderHardwareAddress.length); + this.senderProtocolAddress = new byte[0xff & this.protocolAddressLength]; + bb.get(this.senderProtocolAddress, 0, this.senderProtocolAddress.length); + this.targetHardwareAddress = new byte[0xff & this.hardwareAddressLength]; + bb.get(this.targetHardwareAddress, 0, this.targetHardwareAddress.length); + this.targetProtocolAddress = new byte[0xff & this.protocolAddressLength]; + bb.get(this.targetProtocolAddress, 0, this.targetProtocolAddress.length); + return this; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 13121; + int result = super.hashCode(); + result = prime * result + this.hardwareAddressLength; + result = prime * result + this.hardwareType; + result = prime * result + this.opCode; + result = prime * result + this.protocolAddressLength; + result = prime * result + this.protocolType; + result = prime * result + Arrays.hashCode(this.senderHardwareAddress); + result = prime * result + Arrays.hashCode(this.senderProtocolAddress); + result = prime * result + Arrays.hashCode(this.targetHardwareAddress); + result = prime * result + Arrays.hashCode(this.targetProtocolAddress); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (!(obj instanceof ARP)) { + return false; + } + final ARP other = (ARP) obj; + if (this.hardwareAddressLength != other.hardwareAddressLength) { + return false; + } + if (this.hardwareType != other.hardwareType) { + return false; + } + if (this.opCode != other.opCode) { + return false; + } + if (this.protocolAddressLength != other.protocolAddressLength) { + return false; + } + if (this.protocolType != other.protocolType) { + return false; + } + if (!Arrays.equals(this.senderHardwareAddress, + other.senderHardwareAddress)) { + return false; + } + if (!Arrays.equals(this.senderProtocolAddress, + other.senderProtocolAddress)) { + return false; + } + if (!Arrays.equals(this.targetHardwareAddress, + other.targetHardwareAddress)) { + return false; + } + if (!Arrays.equals(this.targetProtocolAddress, + other.targetProtocolAddress)) { + return false; + } + return true; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "ARP [hardwareType=" + this.hardwareType + ", protocolType=" + + this.protocolType + ", hardwareAddressLength=" + + this.hardwareAddressLength + ", protocolAddressLength=" + + this.protocolAddressLength + ", opCode=" + this.opCode + + ", senderHardwareAddress=" + + Arrays.toString(this.senderHardwareAddress) + + ", senderProtocolAddress=" + + Arrays.toString(this.senderProtocolAddress) + + ", targetHardwareAddress=" + + Arrays.toString(this.targetHardwareAddress) + + ", targetProtocolAddress=" + + Arrays.toString(this.targetProtocolAddress) + "]"; + } + + /** + * Builds an ARP reply based on a request. + * + * @param srcIp the IP address to use as the reply source + * @param srcMac the MAC address to use as the reply source + * @param request the ARP request we got + * @return an Ethernet frame containing the ARP reply + */ + public static Ethernet buildArpReply(Ip4Address srcIp, MacAddress srcMac, + Ethernet request) { + + Ethernet eth = new Ethernet(); + eth.setDestinationMACAddress(request.getSourceMAC()); + eth.setSourceMACAddress(srcMac); + eth.setEtherType(Ethernet.TYPE_ARP); + eth.setVlanID(request.getVlanID()); + + ARP arp = new ARP(); + arp.setOpCode(ARP.OP_REPLY); + arp.setProtocolType(ARP.PROTO_TYPE_IP); + arp.setHardwareType(ARP.HW_TYPE_ETHERNET); + + arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH); + arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH); + arp.setSenderHardwareAddress(srcMac.toBytes()); + arp.setTargetHardwareAddress(request.getSourceMACAddress()); + + arp.setTargetProtocolAddress(((ARP) request.getPayload()) + .getSenderProtocolAddress()); + arp.setSenderProtocolAddress(srcIp.toInt()); + + eth.setPayload(arp); + return eth; + } + + /** + * Deserializer function for ARP packets. + * + * @return deserializer function + */ + public static Deserializer<ARP> deserializer() { + return (data, offset, length) -> { + checkInput(data, offset, length, INITIAL_HEADER_LENGTH); + + ARP arp = new ARP(); + final ByteBuffer bb = ByteBuffer.wrap(data, offset, length); + arp.setHardwareType(bb.getShort()); + arp.setProtocolType(bb.getShort()); + + byte hwAddressLength = bb.get(); + arp.setHardwareAddressLength(hwAddressLength); + + byte protocolAddressLength = bb.get(); + arp.setProtocolAddressLength(protocolAddressLength); + arp.setOpCode(bb.getShort()); + + // Check we have enough space for the addresses + checkHeaderLength(length, INITIAL_HEADER_LENGTH + + 2 * hwAddressLength + + 2 * protocolAddressLength); + + arp.senderHardwareAddress = new byte[0xff & hwAddressLength]; + bb.get(arp.senderHardwareAddress, 0, arp.senderHardwareAddress.length); + arp.senderProtocolAddress = new byte[0xff & protocolAddressLength]; + bb.get(arp.senderProtocolAddress, 0, arp.senderProtocolAddress.length); + arp.targetHardwareAddress = new byte[0xff & hwAddressLength]; + bb.get(arp.targetHardwareAddress, 0, arp.targetHardwareAddress.length); + arp.targetProtocolAddress = new byte[0xff & protocolAddressLength]; + bb.get(arp.targetProtocolAddress, 0, arp.targetProtocolAddress.length); + + return arp; + }; + } + +} |