Renamed registry and packet packages
net.onrc.onos.registry.controller.* => net.onrc.onos.core.registry.*
net.onrc.onos.packet => net.onrc.onos.core.packet
Change-Id: I595e325a2c0bab709f248dde5d84ff7b6185cf8b
diff --git a/src/main/java/net/onrc/onos/core/packet/ARP.java b/src/main/java/net/onrc/onos/core/packet/ARP.java
new file mode 100644
index 0000000..a2e25c3
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/ARP.java
@@ -0,0 +1,316 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class ARP extends BasePacket {
+ public static short HW_TYPE_ETHERNET = 0x1;
+
+ public static short PROTO_TYPE_IP = 0x800;
+
+ public static short OP_REQUEST = 0x1;
+ public static short OP_REPLY = 0x2;
+ public static short OP_RARP_REQUEST = 0x3;
+ public static short OP_RARP_REPLY = 0x4;
+
+ 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 hardwareType;
+ }
+
+ /**
+ * @param hardwareType the hardwareType to set
+ */
+ public ARP setHardwareType(short hardwareType) {
+ this.hardwareType = hardwareType;
+ return this;
+ }
+
+ /**
+ * @return the protocolType
+ */
+ public short getProtocolType() {
+ return protocolType;
+ }
+
+ /**
+ * @param protocolType the protocolType to set
+ */
+ public ARP setProtocolType(short protocolType) {
+ this.protocolType = protocolType;
+ return this;
+ }
+
+ /**
+ * @return the hardwareAddressLength
+ */
+ public byte getHardwareAddressLength() {
+ return hardwareAddressLength;
+ }
+
+ /**
+ * @param hardwareAddressLength the hardwareAddressLength to set
+ */
+ public ARP setHardwareAddressLength(byte hardwareAddressLength) {
+ this.hardwareAddressLength = hardwareAddressLength;
+ return this;
+ }
+
+ /**
+ * @return the protocolAddressLength
+ */
+ public byte getProtocolAddressLength() {
+ return protocolAddressLength;
+ }
+
+ /**
+ * @param protocolAddressLength the protocolAddressLength to set
+ */
+ public ARP setProtocolAddressLength(byte protocolAddressLength) {
+ this.protocolAddressLength = protocolAddressLength;
+ return this;
+ }
+
+ /**
+ * @return the opCode
+ */
+ public short getOpCode() {
+ return opCode;
+ }
+
+ /**
+ * @param opCode the opCode to set
+ */
+ public ARP setOpCode(short opCode) {
+ this.opCode = opCode;
+ return this;
+ }
+
+ /**
+ * @return the senderHardwareAddress
+ */
+ public byte[] getSenderHardwareAddress() {
+ return senderHardwareAddress;
+ }
+
+ /**
+ * @param senderHardwareAddress the senderHardwareAddress to set
+ */
+ public ARP setSenderHardwareAddress(byte[] senderHardwareAddress) {
+ this.senderHardwareAddress = senderHardwareAddress;
+ return this;
+ }
+
+ /**
+ * @return the senderProtocolAddress
+ */
+ public byte[] getSenderProtocolAddress() {
+ return senderProtocolAddress;
+ }
+
+ /**
+ * @param senderProtocolAddress the senderProtocolAddress to set
+ */
+ public ARP setSenderProtocolAddress(byte[] senderProtocolAddress) {
+ this.senderProtocolAddress = senderProtocolAddress;
+ return this;
+ }
+
+ public ARP setSenderProtocolAddress(int address) {
+ this.senderProtocolAddress = ByteBuffer.allocate(4).putInt(address).array();
+ return this;
+ }
+
+ /**
+ * @return the targetHardwareAddress
+ */
+ public byte[] getTargetHardwareAddress() {
+ return targetHardwareAddress;
+ }
+
+ /**
+ * @param targetHardwareAddress the targetHardwareAddress to set
+ */
+ public ARP setTargetHardwareAddress(byte[] targetHardwareAddress) {
+ this.targetHardwareAddress = targetHardwareAddress;
+ return this;
+ }
+
+ /**
+ * @return the targetProtocolAddress
+ */
+ public byte[] getTargetProtocolAddress() {
+ return targetProtocolAddress;
+ }
+
+ /**
+ * @return True if gratuitous ARP (SPA = TPA), false otherwise
+ */
+ public boolean isGratuitous() {
+ assert(senderProtocolAddress.length == targetProtocolAddress.length);
+
+ int indx = 0;
+ while (indx < senderProtocolAddress.length) {
+ if (senderProtocolAddress[indx] != targetProtocolAddress[indx]) {
+ return false;
+ }
+ indx++;
+ }
+
+ return true;
+ }
+
+ /**
+ * @param targetProtocolAddress the targetProtocolAddress to set
+ */
+ public ARP setTargetProtocolAddress(byte[] targetProtocolAddress) {
+ this.targetProtocolAddress = targetProtocolAddress;
+ return this;
+ }
+
+ public ARP setTargetProtocolAddress(int address) {
+ this.targetProtocolAddress = ByteBuffer.allocate(4).putInt(address).array();
+ return this;
+ }
+
+ @Override
+ public byte[] serialize() {
+ int length = 8 + (2 * (0xff & this.hardwareAddressLength))
+ + (2 * (0xff & this.protocolAddressLength));
+ byte[] data = new byte[length];
+ 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(byte[] data, int offset, int length) {
+ 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 + hardwareAddressLength;
+ result = prime * result + hardwareType;
+ result = prime * result + opCode;
+ result = prime * result + protocolAddressLength;
+ result = prime * result + protocolType;
+ result = prime * result + Arrays.hashCode(senderHardwareAddress);
+ result = prime * result + Arrays.hashCode(senderProtocolAddress);
+ result = prime * result + Arrays.hashCode(targetHardwareAddress);
+ result = prime * result + Arrays.hashCode(targetProtocolAddress);
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof ARP))
+ return false;
+ ARP other = (ARP) obj;
+ if (hardwareAddressLength != other.hardwareAddressLength)
+ return false;
+ if (hardwareType != other.hardwareType)
+ return false;
+ if (opCode != other.opCode)
+ return false;
+ if (protocolAddressLength != other.protocolAddressLength)
+ return false;
+ if (protocolType != other.protocolType)
+ return false;
+ if (!Arrays.equals(senderHardwareAddress, other.senderHardwareAddress))
+ return false;
+ if (!Arrays.equals(senderProtocolAddress, other.senderProtocolAddress))
+ return false;
+ if (!Arrays.equals(targetHardwareAddress, other.targetHardwareAddress))
+ return false;
+ if (!Arrays.equals(targetProtocolAddress, other.targetProtocolAddress))
+ return false;
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "ARP [hardwareType=" + hardwareType + ", protocolType="
+ + protocolType + ", hardwareAddressLength="
+ + hardwareAddressLength + ", protocolAddressLength="
+ + protocolAddressLength + ", opCode=" + opCode
+ + ", senderHardwareAddress="
+ + Arrays.toString(senderHardwareAddress)
+ + ", senderProtocolAddress="
+ + Arrays.toString(senderProtocolAddress)
+ + ", targetHardwareAddress="
+ + Arrays.toString(targetHardwareAddress)
+ + ", targetProtocolAddress="
+ + Arrays.toString(targetProtocolAddress) + "]";
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/BPDU.java b/src/main/java/net/onrc/onos/core/packet/BPDU.java
new file mode 100644
index 0000000..1dc7296
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/BPDU.java
@@ -0,0 +1,138 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This class is a Rapid Spanning Tree Protocol
+ * Bridge Protocol Data Unit
+ * @author alexreimers
+ */
+public class BPDU extends BasePacket {
+ public enum BPDUType {
+ CONFIG,
+ TOPOLOGY_CHANGE;
+ }
+
+ private final long destMac = 0x0180c2000000L; // 01-80-c2-00-00-00
+
+ // TODO - check this for RSTP
+ private LLC llcHeader;
+ private short protocolId = 0;
+ private byte version = 0;
+ private byte type;
+ private byte flags;
+ private byte[] rootBridgeId;
+ private int rootPathCost;
+ private byte[] senderBridgeId; // switch cluster MAC
+ private short portId; // port it was transmitted from
+ private short messageAge; // 256ths of a second
+ private short maxAge; // 256ths of a second
+ private short helloTime; // 256ths of a second
+ private short forwardDelay; // 256ths of a second
+
+ public BPDU(BPDUType type) {
+ rootBridgeId = new byte[8];
+ senderBridgeId = new byte[8];
+
+ llcHeader = new LLC();
+ llcHeader.setDsap((byte) 0x42);
+ llcHeader.setSsap((byte) 0x42);
+ llcHeader.setCtrl((byte) 0x03);
+
+ switch(type) {
+ case CONFIG:
+ this.type = 0x0;
+ break;
+ case TOPOLOGY_CHANGE:
+ this.type = (byte) 0x80; // 1000 0000
+ break;
+ default:
+ this.type = 0;
+ break;
+ }
+ }
+
+ @Override
+ public byte[] serialize() {
+ byte[] data;
+ // TODO check these
+ if (type == 0x0) {
+ // config
+ data = new byte[38];
+ } else {
+ // topology change
+ data = new byte[7]; // LLC + TC notification
+ }
+
+ ByteBuffer bb = ByteBuffer.wrap(data);
+ // Serialize the LLC header
+ byte[] llc = llcHeader.serialize();
+ bb.put(llc, 0, llc.length);
+ bb.putShort(protocolId);
+ bb.put(version);
+ bb.put(type);
+
+ if (type == 0x0) {
+ bb.put(flags);
+ bb.put(rootBridgeId, 0, rootBridgeId.length);
+ bb.putInt(rootPathCost);
+ bb.put(senderBridgeId, 0, senderBridgeId.length);
+ bb.putShort(portId);
+ bb.putShort(messageAge);
+ bb.putShort(maxAge);
+ bb.putShort(helloTime);
+ bb.putShort(forwardDelay);
+ }
+
+ return data;
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+
+ // LLC header
+ llcHeader.deserialize(data, offset, 3);
+
+ this.protocolId = bb.getShort();
+ this.version = bb.get();
+ this.type = bb.get();
+
+ // These fields only exist if it's a configuration BPDU
+ if (this.type == 0x0) {
+ this.flags = bb.get();
+ bb.get(rootBridgeId, 0, 6);
+ this.rootPathCost = bb.getInt();
+ bb.get(this.senderBridgeId, 0, 6);
+ this.portId = bb.getShort();
+ this.messageAge = bb.getShort();
+ this.maxAge = bb.getShort();
+ this.helloTime = bb.getShort();
+ this.forwardDelay = bb.getShort();
+ }
+ // TODO should we set other fields to 0?
+
+ return this;
+ }
+
+ public long getDestMac() {
+ return destMac;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/BSN.java b/src/main/java/net/onrc/onos/core/packet/BSN.java
new file mode 100644
index 0000000..fead254
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/BSN.java
@@ -0,0 +1,172 @@
+/**
+* Copyright 2012, Big Switch Networks, Inc.
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Shudong Zhou (shudong.zhou@bigswitch.com)
+ *
+ */
+public class BSN extends BasePacket {
+ public static final int BSN_MAGIC = 0x20000604;
+ public static final short BSN_VERSION_CURRENT = 0x0;
+ public static final short BSN_TYPE_PROBE = 0x1;
+ public static final short BSN_TYPE_BDDP = 0x2;
+ public static Map<Short, Class<? extends IPacket>> typeClassMap;
+
+ static {
+ typeClassMap = new HashMap<Short, Class<? extends IPacket>>();
+ typeClassMap.put(BSN_TYPE_PROBE, BSNPROBE.class);
+ typeClassMap.put(BSN_TYPE_BDDP, LLDP.class);
+ }
+
+ protected short type;
+ protected short version;
+
+ public BSN() {
+ version = BSN_VERSION_CURRENT;
+ }
+
+ public BSN(short type) {
+ this.type = type;
+ version = BSN_VERSION_CURRENT;
+ }
+
+ public short getType() {
+ return type;
+ }
+
+ public BSN setType(short type) {
+ this.type = type;
+ return this;
+ }
+
+ public short getVersion() {
+ return version;
+ }
+
+ public BSN setVersion(short version) {
+ this.version = version;
+ return this;
+ }
+
+ @Override
+ public byte[] serialize() {
+ short length = 4 /* magic */ + 2 /* type */ + 2 /* version */;
+
+ byte[] payloadData = null;
+ if (this.payload != null) {
+ payload.setParent(this);
+ payloadData = payload.serialize();
+ length += payloadData.length;
+ }
+
+ byte[] data = new byte[length];
+ ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.putInt(BSN_MAGIC);
+ bb.putShort(this.type);
+ bb.putShort(this.version);
+ if (payloadData != null)
+ bb.put(payloadData);
+
+ if (this.parent != null && this.parent instanceof Ethernet)
+ ((Ethernet)this.parent).setEtherType(Ethernet.TYPE_BSN);
+
+ return data;
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+
+ int magic = bb.getInt();
+ if (magic != BSN_MAGIC) {
+ throw new RuntimeException("Invalid BSN magic " + magic);
+ }
+
+ this.type = bb.getShort();
+ this.version = bb.getShort();
+ if (this.version != BSN_VERSION_CURRENT) {
+ throw new RuntimeException(
+ "Invalid BSN packet version " + this.version + ", should be "
+ + BSN_VERSION_CURRENT);
+ }
+
+ IPacket payload;
+ if (typeClassMap.containsKey(this.type)) {
+ Class<? extends IPacket> clazz = typeClassMap.get(this.type);
+ try {
+ payload = clazz.newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("Error parsing payload for BSN packet" + e);
+ }
+ } else {
+ payload = new Data();
+ }
+
+ this.payload = new Data();
+ this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position());
+ this.payload.setParent(this);
+
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 883;
+ int result = super.hashCode();
+ result = prime * result + version;
+ result = prime * result + type;
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof BSN))
+ return false;
+ BSN other = (BSN) obj;
+ return (type == other.type &&
+ version == other.version);
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer("\n");
+ sb.append("BSN packet");
+ if (typeClassMap.containsKey(this.type))
+ sb.append(" type: " + typeClassMap.get(this.type).getCanonicalName());
+ else
+ sb.append(" type: " + this.type);
+
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/BSNPROBE.java b/src/main/java/net/onrc/onos/core/packet/BSNPROBE.java
new file mode 100644
index 0000000..941a240
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/BSNPROBE.java
@@ -0,0 +1,197 @@
+/**
+* Copyright 2012, Big Switch Networks, Inc.
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import org.openflow.util.HexString;
+
+/**
+ * @author Shudong Zhou (shudong.zhou@bigswitch.com)
+ *
+ */
+public class BSNPROBE extends BasePacket {
+ protected long controllerId;
+ protected int sequenceId;
+ protected byte[] srcMac;
+ protected byte[] dstMac;
+ protected long srcSwDpid;
+ protected int srcPortNo;
+
+ public BSNPROBE() {
+ srcMac = new byte[6];
+ dstMac = new byte[6];
+ }
+
+
+ public long getControllerId() {
+ return this.controllerId;
+ }
+
+ public BSNPROBE setControllerId(long controllerId) {
+ this.controllerId = controllerId;
+ return this;
+ }
+
+ public int getSequenceId() {
+ return sequenceId;
+ }
+
+ public BSNPROBE setSequenceId(int sequenceId) {
+ this.sequenceId = sequenceId;
+ return this;
+ }
+
+ public byte[] getSrcMac() {
+ return this.srcMac;
+ }
+
+ public BSNPROBE setSrcMac(byte[] srcMac) {
+ this.srcMac = srcMac;
+ return this;
+ }
+
+ public byte[] getDstMac() {
+ return dstMac;
+ }
+
+ public BSNPROBE setDstMac(byte[] dstMac) {
+ this.dstMac = dstMac;
+ return this;
+ }
+
+ public long getSrcSwDpid() {
+ return srcSwDpid;
+ }
+
+ public BSNPROBE setSrcSwDpid(long srcSwDpid) {
+ this.srcSwDpid = srcSwDpid;
+ return this;
+ }
+
+ public int getSrcPortNo() {
+ return srcPortNo;
+ }
+
+ public BSNPROBE setSrcPortNo(int srcPortNo) {
+ this.srcPortNo = srcPortNo;
+ return this;
+ }
+
+ @Override
+ public byte[] serialize() {
+ short length = 8 /* controllerId */ + 4 /* seqId */
+ + 12 /* srcMac dstMac */ + 8 /* srcSwDpid */ + 4 /* srcPortNo */;
+
+ byte[] payloadData = null;
+ if (this.payload != null) {
+ payload.setParent(this);
+ payloadData = payload.serialize();
+ length += payloadData.length;
+ }
+
+ byte[] data = new byte[length];
+ ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.putLong(this.controllerId);
+ bb.putInt(this.sequenceId);
+ bb.put(this.srcMac);
+ bb.put(this.dstMac);
+ bb.putLong(this.srcSwDpid);
+ bb.putInt(this.srcPortNo);
+ if (payloadData != null)
+ bb.put(payloadData);
+
+ if (this.parent != null && this.parent instanceof BSN)
+ ((BSN)this.parent).setType(BSN.BSN_TYPE_PROBE);
+
+ return data;
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+
+ controllerId = bb.getLong();
+ sequenceId = bb.getInt();
+ bb.get(this.srcMac, 0, 6);
+ bb.get(this.dstMac, 0, 6);
+ this.srcSwDpid = bb.getLong();
+ this.srcPortNo = bb.getInt();
+
+ if (bb.hasRemaining()) {
+ this.payload = new Data();
+ this.payload = payload.deserialize(data, bb.position(), bb.limit() - bb.position());
+ this.payload.setParent(this);
+ }
+
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 883;
+ int result = super.hashCode();
+ result = prime * result + srcMac.hashCode();
+ result = prime * result + dstMac.hashCode();
+ result = prime * result + (int) (srcSwDpid >> 32) + (int) srcSwDpid;
+ result = prime * result + srcPortNo;
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof BSNPROBE))
+ return false;
+ BSNPROBE other = (BSNPROBE) obj;
+ if (!Arrays.equals(srcMac, other.srcMac))
+ return false;
+ if (!Arrays.equals(dstMac, other.dstMac))
+ return false;
+ return (sequenceId == other.sequenceId &&
+ srcSwDpid == other.srcSwDpid &&
+ srcPortNo == other.srcPortNo
+ );
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer("\n");
+ sb.append("BSN Probe packet");
+ sb.append("\nSource Mac: ");
+ sb.append(HexString.toHexString(srcMac));
+ sb.append("\nDestination Mac: ");
+ sb.append(HexString.toHexString(dstMac));
+ sb.append("\nSource Switch: ");
+ sb.append(HexString.toHexString(srcSwDpid));
+ sb.append(" port: " + srcPortNo);
+ sb.append("\nSequence No.:" + sequenceId);
+
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/BasePacket.java b/src/main/java/net/onrc/onos/core/packet/BasePacket.java
new file mode 100644
index 0000000..d3b382b
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/BasePacket.java
@@ -0,0 +1,116 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+
+/**
+*
+* @author David Erickson (daviderickson@cs.stanford.edu)
+*/
+public abstract class BasePacket implements IPacket {
+ protected IPacket parent;
+ protected IPacket payload;
+
+ /**
+ * @return the parent
+ */
+ @Override
+ public IPacket getParent() {
+ return parent;
+ }
+
+ /**
+ * @param parent the parent to set
+ */
+ @Override
+ public IPacket setParent(IPacket parent) {
+ this.parent = parent;
+ return this;
+ }
+
+ /**
+ * @return the payload
+ */
+ @Override
+ public IPacket getPayload() {
+ return payload;
+ }
+
+ /**
+ * @param payload the payload to set
+ */
+ @Override
+ public IPacket setPayload(IPacket payload) {
+ this.payload = payload;
+ return this;
+ }
+
+ @Override
+ public void resetChecksum() {
+ if (this.parent != null)
+ this.parent.resetChecksum();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 6733;
+ int result = 1;
+ result = prime * result + ((payload == null) ? 0 : payload.hashCode());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof BasePacket))
+ return false;
+ BasePacket other = (BasePacket) obj;
+ if (payload == null) {
+ if (other.payload != null)
+ return false;
+ } else if (!payload.equals(other.payload))
+ return false;
+ return true;
+ }
+
+ @Override
+ public Object clone() {
+ IPacket pkt;
+ try {
+ pkt = this.getClass().newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("Could not clone packet");
+ }
+ // TODO: we are using serialize()/deserialize() to perform the
+ // cloning. Not the most efficient way but simple. We can revisit
+ // if we hit performance problems.
+ byte[] data = this.serialize();
+ pkt.deserialize(this.serialize(), 0, data.length);
+ pkt.setParent(this.parent);
+ return pkt;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/onrc/onos/core/packet/DHCP.java b/src/main/java/net/onrc/onos/core/packet/DHCP.java
new file mode 100644
index 0000000..16cc22f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/DHCP.java
@@ -0,0 +1,517 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class DHCP extends BasePacket {
+ /**
+ * ------------------------------------------
+ * |op (1) | htype(1) | hlen(1) | hops(1) |
+ * ------------------------------------------
+ * | xid (4) |
+ * ------------------------------------------
+ * | secs (2) | flags (2) |
+ * ------------------------------------------
+ * | ciaddr (4) |
+ * ------------------------------------------
+ * | yiaddr (4) |
+ * ------------------------------------------
+ * | siaddr (4) |
+ * ------------------------------------------
+ * | giaddr (4) |
+ * ------------------------------------------
+ * | chaddr (16) |
+ * ------------------------------------------
+ * | sname (64) |
+ * ------------------------------------------
+ * | file (128) |
+ * ------------------------------------------
+ * | options (312) |
+ * ------------------------------------------
+ *
+ */
+ // Header + magic without options
+ public static int MIN_HEADER_LENGTH = 240;
+ public static byte OPCODE_REQUEST = 0x1;
+ public static byte OPCODE_REPLY = 0x2;
+
+ public static byte HWTYPE_ETHERNET = 0x1;
+
+ public enum DHCPOptionCode {
+ OptionCode_SubnetMask ((byte)1),
+ OptionCode_RequestedIP ((byte)50),
+ OptionCode_LeaseTime ((byte)51),
+ OptionCode_MessageType ((byte)53),
+ OptionCode_DHCPServerIp ((byte)54),
+ OptionCode_RequestedParameters ((byte)55),
+ OptionCode_RenewalTime ((byte)58),
+ OPtionCode_RebindingTime ((byte)59),
+ OptionCode_ClientID ((byte)61),
+ OptionCode_END ((byte)255);
+
+ protected byte value;
+
+ private DHCPOptionCode(byte value) {
+ this.value = value;
+ }
+
+ public byte getValue() {
+ return value;
+ }
+ }
+
+ protected byte opCode;
+ protected byte hardwareType;
+ protected byte hardwareAddressLength;
+ protected byte hops;
+ protected int transactionId;
+ protected short seconds;
+ protected short flags;
+ protected int clientIPAddress;
+ protected int yourIPAddress;
+ protected int serverIPAddress;
+ protected int gatewayIPAddress;
+ protected byte[] clientHardwareAddress;
+ protected String serverName;
+ protected String bootFileName;
+ protected List<DHCPOption> options = new ArrayList<DHCPOption>();
+
+ /**
+ * @return the opCode
+ */
+ public byte getOpCode() {
+ return opCode;
+ }
+
+ /**
+ * @param opCode the opCode to set
+ */
+ public DHCP setOpCode(byte opCode) {
+ this.opCode = opCode;
+ return this;
+ }
+
+ /**
+ * @return the hardwareType
+ */
+ public byte getHardwareType() {
+ return hardwareType;
+ }
+
+ /**
+ * @param hardwareType the hardwareType to set
+ */
+ public DHCP setHardwareType(byte hardwareType) {
+ this.hardwareType = hardwareType;
+ return this;
+ }
+
+ /**
+ * @return the hardwareAddressLength
+ */
+ public byte getHardwareAddressLength() {
+ return hardwareAddressLength;
+ }
+
+ /**
+ * @param hardwareAddressLength the hardwareAddressLength to set
+ */
+ public DHCP setHardwareAddressLength(byte hardwareAddressLength) {
+ this.hardwareAddressLength = hardwareAddressLength;
+ return this;
+ }
+
+ /**
+ * @return the hops
+ */
+ public byte getHops() {
+ return hops;
+ }
+
+ /**
+ * @param hops the hops to set
+ */
+ public DHCP setHops(byte hops) {
+ this.hops = hops;
+ return this;
+ }
+
+ /**
+ * @return the transactionId
+ */
+ public int getTransactionId() {
+ return transactionId;
+ }
+
+ /**
+ * @param transactionId the transactionId to set
+ */
+ public DHCP setTransactionId(int transactionId) {
+ this.transactionId = transactionId;
+ return this;
+ }
+
+ /**
+ * @return the seconds
+ */
+ public short getSeconds() {
+ return seconds;
+ }
+
+ /**
+ * @param seconds the seconds to set
+ */
+ public DHCP setSeconds(short seconds) {
+ this.seconds = seconds;
+ return this;
+ }
+
+ /**
+ * @return the flags
+ */
+ public short getFlags() {
+ return flags;
+ }
+
+ /**
+ * @param flags the flags to set
+ */
+ public DHCP setFlags(short flags) {
+ this.flags = flags;
+ return this;
+ }
+
+ /**
+ * @return the clientIPAddress
+ */
+ public int getClientIPAddress() {
+ return clientIPAddress;
+ }
+
+ /**
+ * @param clientIPAddress the clientIPAddress to set
+ */
+ public DHCP setClientIPAddress(int clientIPAddress) {
+ this.clientIPAddress = clientIPAddress;
+ return this;
+ }
+
+ /**
+ * @return the yourIPAddress
+ */
+ public int getYourIPAddress() {
+ return yourIPAddress;
+ }
+
+ /**
+ * @param yourIPAddress the yourIPAddress to set
+ */
+ public DHCP setYourIPAddress(int yourIPAddress) {
+ this.yourIPAddress = yourIPAddress;
+ return this;
+ }
+
+ /**
+ * @return the serverIPAddress
+ */
+ public int getServerIPAddress() {
+ return serverIPAddress;
+ }
+
+ /**
+ * @param serverIPAddress the serverIPAddress to set
+ */
+ public DHCP setServerIPAddress(int serverIPAddress) {
+ this.serverIPAddress = serverIPAddress;
+ return this;
+ }
+
+ /**
+ * @return the gatewayIPAddress
+ */
+ public int getGatewayIPAddress() {
+ return gatewayIPAddress;
+ }
+
+ /**
+ * @param gatewayIPAddress the gatewayIPAddress to set
+ */
+ public DHCP setGatewayIPAddress(int gatewayIPAddress) {
+ this.gatewayIPAddress = gatewayIPAddress;
+ return this;
+ }
+
+ /**
+ * @return the clientHardwareAddress
+ */
+ public byte[] getClientHardwareAddress() {
+ return clientHardwareAddress;
+ }
+
+ /**
+ * @param clientHardwareAddress the clientHardwareAddress to set
+ */
+ public DHCP setClientHardwareAddress(byte[] clientHardwareAddress) {
+ this.clientHardwareAddress = clientHardwareAddress;
+ return this;
+ }
+
+ /**
+ * Gets a specific DHCP option parameter
+ * @param opetionCode The option code to get
+ * @return The value of the option if it exists, null otherwise
+ */
+ public DHCPOption getOption(DHCPOptionCode optionCode) {
+ for (DHCPOption opt : options) {
+ if (opt.code == optionCode.value)
+ return opt;
+ }
+ return null;
+ }
+
+ /**
+ * @return the options
+ */
+ public List<DHCPOption> getOptions() {
+ return options;
+ }
+
+ /**
+ * @param options the options to set
+ */
+ public DHCP setOptions(List<DHCPOption> options) {
+ this.options = options;
+ return this;
+ }
+
+ /**
+ * @return the packetType base on option 53
+ */
+ public DHCPPacketType getPacketType() {
+ ListIterator<DHCPOption> lit = options.listIterator();
+ while (lit.hasNext()) {
+ DHCPOption option = lit.next();
+ // only care option 53
+ if (option.getCode() == 53) {
+ return DHCPPacketType.getType(option.getData()[0]);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return the serverName
+ */
+ public String getServerName() {
+ return serverName;
+ }
+
+ /**
+ * @param serverName the serverName to set
+ */
+ public DHCP setServerName(String serverName) {
+ this.serverName = serverName;
+ return this;
+ }
+
+ /**
+ * @return the bootFileName
+ */
+ public String getBootFileName() {
+ return bootFileName;
+ }
+
+ /**
+ * @param bootFileName the bootFileName to set
+ */
+ public DHCP setBootFileName(String bootFileName) {
+ this.bootFileName = bootFileName;
+ return this;
+ }
+
+ @Override
+ public byte[] serialize() {
+ // not guaranteed to retain length/exact format
+ resetChecksum();
+
+ // minimum size 240 including magic cookie, options generally padded to 300
+ int optionsLength = 0;
+ for (DHCPOption option : this.options) {
+ if (option.getCode() == 0 || option.getCode() == 255) {
+ optionsLength += 1;
+ } else {
+ optionsLength += 2 + (int)(0xff & option.getLength());
+ }
+ }
+ int optionsPadLength = 0;
+ if (optionsLength < 60)
+ optionsPadLength = 60 - optionsLength;
+
+ byte[] data = new byte[240+optionsLength+optionsPadLength];
+ ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.put(this.opCode);
+ bb.put(this.hardwareType);
+ bb.put(this.hardwareAddressLength);
+ bb.put(this.hops);
+ bb.putInt(this.transactionId);
+ bb.putShort(this.seconds);
+ bb.putShort(this.flags);
+ bb.putInt(this.clientIPAddress);
+ bb.putInt(this.yourIPAddress);
+ bb.putInt(this.serverIPAddress);
+ bb.putInt(this.gatewayIPAddress);
+ bb.put(this.clientHardwareAddress);
+ if (this.clientHardwareAddress.length < 16) {
+ for (int i = 0; i < (16 - this.clientHardwareAddress.length); ++i) {
+ bb.put((byte) 0x0);
+ }
+ }
+ writeString(this.serverName, bb, 64);
+ writeString(this.bootFileName, bb, 128);
+ // magic cookie
+ bb.put((byte) 0x63);
+ bb.put((byte) 0x82);
+ bb.put((byte) 0x53);
+ bb.put((byte) 0x63);
+ for (DHCPOption option : this.options) {
+ int code = option.getCode() & 0xff;
+ bb.put((byte) code);
+ if ((code != 0) && (code != 255)) {
+ bb.put(option.getLength());
+ bb.put(option.getData());
+ }
+ }
+ // assume the rest is padded out with zeroes
+ return data;
+ }
+
+ protected void writeString(String string, ByteBuffer bb, int maxLength) {
+ if (string == null) {
+ for (int i = 0; i < maxLength; ++i) {
+ bb.put((byte) 0x0);
+ }
+ } else {
+ byte[] bytes = null;
+ try {
+ bytes = string.getBytes("ascii");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("Failure encoding server name", e);
+ }
+ int writeLength = bytes.length;
+ if (writeLength > maxLength) {
+ writeLength = maxLength;
+ }
+ bb.put(bytes, 0, writeLength);
+ for (int i = writeLength; i < maxLength; ++i) {
+ bb.put((byte) 0x0);
+ }
+ }
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+ if (bb.remaining() < MIN_HEADER_LENGTH) {
+ return this;
+ }
+
+ this.opCode = bb.get();
+ this.hardwareType = bb.get();
+ this.hardwareAddressLength = bb.get();
+ this.hops = bb.get();
+ this.transactionId = bb.getInt();
+ this.seconds = bb.getShort();
+ this.flags = bb.getShort();
+ this.clientIPAddress = bb.getInt();
+ this.yourIPAddress = bb.getInt();
+ this.serverIPAddress = bb.getInt();
+ this.gatewayIPAddress = bb.getInt();
+ int hardwareAddressLength = 0xff & this.hardwareAddressLength;
+ this.clientHardwareAddress = new byte[hardwareAddressLength];
+
+ bb.get(this.clientHardwareAddress);
+ for (int i = hardwareAddressLength; i < 16; ++i)
+ bb.get();
+ this.serverName = readString(bb, 64);
+ this.bootFileName = readString(bb, 128);
+ // read the magic cookie
+ // magic cookie
+ bb.get();
+ bb.get();
+ bb.get();
+ bb.get();
+ // read options
+ while (bb.hasRemaining()) {
+ DHCPOption option = new DHCPOption();
+ int code = 0xff & bb.get(); // convert signed byte to int in range [0,255]
+ option.setCode((byte) code);
+ if (code == 0) {
+ // skip these
+ continue;
+ } else if (code != 255) {
+ if (bb.hasRemaining()) {
+ int l = 0xff & bb.get(); // convert signed byte to int in range [0,255]
+ option.setLength((byte) l);
+ if (bb.remaining() >= l) {
+ byte[] optionData = new byte[l];
+ bb.get(optionData);
+ option.setData(optionData);
+ } else {
+ // Skip the invalid option and set the END option
+ code = 0xff;
+ option.setCode((byte)code);
+ option.setLength((byte) 0);
+ }
+ } else {
+ // Skip the invalid option and set the END option
+ code = 0xff;
+ option.setCode((byte)code);
+ option.setLength((byte) 0);
+ }
+ }
+ this.options.add(option);
+ if (code == 255) {
+ // remaining bytes are supposed to be 0, but ignore them just in case
+ break;
+ }
+ }
+
+ return this;
+ }
+
+ protected String readString(ByteBuffer bb, int maxLength) {
+ byte[] bytes = new byte[maxLength];
+ bb.get(bytes);
+ String result = null;
+ try {
+ result = new String(bytes, "ascii").trim();
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("Failure decoding string", e);
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/DHCPOption.java b/src/main/java/net/onrc/onos/core/packet/DHCPOption.java
new file mode 100644
index 0000000..4681e0b
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/DHCPOption.java
@@ -0,0 +1,118 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.util.Arrays;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class DHCPOption {
+ protected byte code;
+ protected byte length;
+ protected byte[] data;
+
+ /**
+ * @return the code
+ */
+ public byte getCode() {
+ return code;
+ }
+
+ /**
+ * @param code the code to set
+ */
+ public DHCPOption setCode(byte code) {
+ this.code = code;
+ return this;
+ }
+
+ /**
+ * @return the length
+ */
+ public byte getLength() {
+ return length;
+ }
+
+ /**
+ * @param length the length to set
+ */
+ public DHCPOption setLength(byte length) {
+ this.length = length;
+ return this;
+ }
+
+ /**
+ * @return the data
+ */
+ public byte[] getData() {
+ return data;
+ }
+
+ /**
+ * @param data the data to set
+ */
+ public DHCPOption setData(byte[] data) {
+ this.data = data;
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + code;
+ result = prime * result + Arrays.hashCode(data);
+ result = prime * result + length;
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof DHCPOption))
+ return false;
+ DHCPOption other = (DHCPOption) obj;
+ if (code != other.code)
+ return false;
+ if (!Arrays.equals(data, other.data))
+ return false;
+ if (length != other.length)
+ return false;
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "DHCPOption [code=" + code + ", length=" + length + ", data="
+ + Arrays.toString(data) + "]";
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/DHCPPacketType.java b/src/main/java/net/onrc/onos/core/packet/DHCPPacketType.java
new file mode 100644
index 0000000..d68c22f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/DHCPPacketType.java
@@ -0,0 +1,116 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+public enum DHCPPacketType {
+ // From RFC 1533
+ DHCPDISCOVER (1),
+ DHCPOFFER (2),
+ DHCPREQUEST (3),
+ DHCPDECLINE (4),
+ DHCPACK (5),
+ DHCPNAK (6),
+ DHCPRELEASE (7),
+
+ // From RFC2132
+ DHCPINFORM (8),
+
+ // From RFC3203
+ DHCPFORCERENEW (9),
+
+ // From RFC4388
+ DHCPLEASEQUERY (10),
+ DHCPLEASEUNASSIGNED (11),
+ DHCPLEASEUNKNOWN (12),
+ DHCPLEASEACTIVE (13);
+
+ protected int value;
+
+ private DHCPPacketType(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public String toString(){
+ switch (value) {
+ case 1:
+ return "DHCPDISCOVER";
+ case 2:
+ return "DHCPOFFER";
+ case 3:
+ return "DHCPREQUEST";
+ case 4:
+ return "DHCPDECLINE";
+ case 5:
+ return "DHCPACK";
+ case 6:
+ return "DHCPNAK";
+ case 7:
+ return "DHCPRELEASE";
+ case 8:
+ return "DHCPINFORM";
+ case 9:
+ return "DHCPFORCERENEW";
+ case 10:
+ return "DHCPLEASEQUERY";
+ case 11:
+ return "DHCPLEASEUNASSIGNED";
+ case 12:
+ return "DHCPLEASEUNKNOWN";
+ case 13:
+ return "DHCPLEASEACTIVE";
+ }
+
+ return null;
+ }
+ public static DHCPPacketType getType(int value) {
+ switch (value) {
+ case 1:
+ return DHCPDISCOVER;
+ case 2:
+ return DHCPOFFER;
+ case 3:
+ return DHCPREQUEST;
+ case 4:
+ return DHCPDECLINE;
+ case 5:
+ return DHCPACK;
+ case 6:
+ return DHCPNAK;
+ case 7:
+ return DHCPRELEASE;
+ case 8:
+ return DHCPINFORM;
+ case 9:
+ return DHCPFORCERENEW;
+ case 10:
+ return DHCPLEASEQUERY;
+ case 11:
+ return DHCPLEASEUNASSIGNED;
+ case 12:
+ return DHCPLEASEUNKNOWN;
+ case 13:
+ return DHCPLEASEACTIVE;
+ }
+
+ return null;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/Data.java b/src/main/java/net/onrc/onos/core/packet/Data.java
new file mode 100644
index 0000000..e8617ad
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/Data.java
@@ -0,0 +1,94 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.util.Arrays;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class Data extends BasePacket {
+ protected byte[] data;
+
+ /**
+ *
+ */
+ public Data() {
+ }
+
+ /**
+ * @param data
+ */
+ public Data(byte[] data) {
+ this.data = data;
+ }
+
+ /**
+ * @return the data
+ */
+ public byte[] getData() {
+ return data;
+ }
+
+ /**
+ * @param data the data to set
+ */
+ public Data setData(byte[] data) {
+ this.data = data;
+ return this;
+ }
+
+ public byte[] serialize() {
+ return this.data;
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ this.data = Arrays.copyOfRange(data, offset, data.length);
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 1571;
+ int result = super.hashCode();
+ result = prime * result + Arrays.hashCode(data);
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof Data))
+ return false;
+ Data other = (Data) obj;
+ if (!Arrays.equals(data, other.data))
+ return false;
+ return true;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/Ethernet.java b/src/main/java/net/onrc/onos/core/packet/Ethernet.java
new file mode 100644
index 0000000..be37380
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/Ethernet.java
@@ -0,0 +1,468 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.floodlightcontroller.util.MACAddress;
+import org.openflow.util.HexString;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class Ethernet extends BasePacket {
+ private static String HEXES = "0123456789ABCDEF";
+ public static final short TYPE_ARP = 0x0806;
+ public static final short TYPE_RARP = (short) 0x8035;
+ public static final short TYPE_IPv4 = 0x0800;
+ public static final short TYPE_LLDP = (short) 0x88cc;
+ public static final short TYPE_BSN = (short) 0x8942;
+ public static final short VLAN_UNTAGGED = (short)0xffff;
+ public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
+ public static Map<Short, Class<? extends IPacket>> etherTypeClassMap;
+
+ static {
+ etherTypeClassMap = new HashMap<Short, Class<? extends IPacket>>();
+ etherTypeClassMap.put(TYPE_ARP, ARP.class);
+ etherTypeClassMap.put(TYPE_RARP, ARP.class);
+ etherTypeClassMap.put(TYPE_IPv4, IPv4.class);
+ etherTypeClassMap.put(TYPE_LLDP, LLDP.class);
+ etherTypeClassMap.put(TYPE_BSN, BSN.class);
+ }
+
+ protected MACAddress destinationMACAddress;
+ protected MACAddress sourceMACAddress;
+ protected byte priorityCode;
+ protected short vlanID;
+ protected short etherType;
+ protected boolean pad = false;
+
+ /**
+ * By default, set Ethernet to untagged
+ */
+ public Ethernet() {
+ super();
+ this.vlanID = VLAN_UNTAGGED;
+ }
+
+ /**
+ * @return the destination MAC as a byte array
+ */
+ public byte[] getDestinationMACAddress() {
+ return destinationMACAddress.toBytes();
+ }
+
+ /**
+ * @return the destination MAC
+ */
+ public MACAddress getDestinationMAC() {
+ return destinationMACAddress;
+ }
+
+ /**
+ * @param destinationMACAddress the destination MAC to set
+ */
+ public Ethernet setDestinationMACAddress(byte[] destinationMACAddress) {
+ this.destinationMACAddress = MACAddress.valueOf(destinationMACAddress);
+ return this;
+ }
+
+ /**
+ * @param destinationMACAddress the destination MAC to set
+ */
+ public Ethernet setDestinationMACAddress(String destinationMACAddress) {
+ this.destinationMACAddress = MACAddress.valueOf(destinationMACAddress);
+ return this;
+ }
+
+ /**
+ * @return the source MACAddress as a byte array
+ */
+ public byte[] getSourceMACAddress() {
+ return sourceMACAddress.toBytes();
+ }
+
+ /**
+ * @return the source MACAddress
+ */
+ public MACAddress getSourceMAC() {
+ return sourceMACAddress;
+ }
+
+ /**
+ * @param sourceMACAddress the source MAC to set
+ */
+ public Ethernet setSourceMACAddress(byte[] sourceMACAddress) {
+ this.sourceMACAddress = MACAddress.valueOf(sourceMACAddress);
+ return this;
+ }
+
+ /**
+ * @param sourceMACAddress the source MAC to set
+ */
+ public Ethernet setSourceMACAddress(String sourceMACAddress) {
+ this.sourceMACAddress = MACAddress.valueOf(sourceMACAddress);
+ return this;
+ }
+
+ /**
+ * @return the priorityCode
+ */
+ public byte getPriorityCode() {
+ return priorityCode;
+ }
+
+ /**
+ * @param priorityCode the priorityCode to set
+ */
+ public Ethernet setPriorityCode(byte priorityCode) {
+ this.priorityCode = priorityCode;
+ return this;
+ }
+
+ /**
+ * @return the vlanID
+ */
+ public short getVlanID() {
+ return vlanID;
+ }
+
+ /**
+ * @param vlanID the vlanID to set
+ */
+ public Ethernet setVlanID(short vlanID) {
+ this.vlanID = vlanID;
+ return this;
+ }
+
+ /**
+ * @return the etherType
+ */
+ public short getEtherType() {
+ return etherType;
+ }
+
+ /**
+ * @param etherType the etherType to set
+ */
+ public Ethernet setEtherType(short etherType) {
+ this.etherType = etherType;
+ return this;
+ }
+
+ /**
+ * @return True if the Ethernet frame is broadcast, false otherwise
+ */
+ public boolean isBroadcast() {
+ assert(destinationMACAddress.length() == 6);
+ return destinationMACAddress.isBroadcast();
+ }
+
+ /**
+ * @return True is the Ethernet frame is multicast, False otherwise
+ */
+ public boolean isMulticast() {
+ return destinationMACAddress.isMulticast();
+ }
+ /**
+ * Pad this packet to 60 bytes minimum, filling with zeros?
+ * @return the pad
+ */
+ public boolean isPad() {
+ return pad;
+ }
+
+ /**
+ * Pad this packet to 60 bytes minimum, filling with zeros?
+ * @param pad the pad to set
+ */
+ public Ethernet setPad(boolean pad) {
+ this.pad = pad;
+ return this;
+ }
+
+ public byte[] serialize() {
+ byte[] payloadData = null;
+ if (payload != null) {
+ payload.setParent(this);
+ payloadData = payload.serialize();
+ }
+ int length = 14 + ((vlanID == VLAN_UNTAGGED) ? 0 : 4) +
+ ((payloadData == null) ? 0 : payloadData.length);
+ if (pad && length < 60) {
+ length = 60;
+ }
+ byte[] data = new byte[length];
+ ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.put(destinationMACAddress.toBytes());
+ bb.put(sourceMACAddress.toBytes());
+ if (vlanID != VLAN_UNTAGGED) {
+ bb.putShort((short) 0x8100);
+ bb.putShort((short) ((priorityCode << 13) | (vlanID & 0x0fff)));
+ }
+ bb.putShort(etherType);
+ if (payloadData != null)
+ bb.put(payloadData);
+ if (pad) {
+ Arrays.fill(data, bb.position(), data.length, (byte)0x0);
+ }
+ return data;
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ if (length <= 0)
+ return null;
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+ if (this.destinationMACAddress == null)
+ this.destinationMACAddress = MACAddress.valueOf(new byte[6]);
+ byte[] dstAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH];
+ bb.get(dstAddr);
+ this.destinationMACAddress = MACAddress.valueOf(dstAddr);
+
+ if (this.sourceMACAddress == null)
+ this.sourceMACAddress = MACAddress.valueOf(new byte[6]);
+ byte[] srcAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH];
+ bb.get(srcAddr);
+ this.sourceMACAddress = MACAddress.valueOf(srcAddr);
+
+ short etherType = bb.getShort();
+ if (etherType == (short) 0x8100) {
+ short tci = bb.getShort();
+ this.priorityCode = (byte) ((tci >> 13) & 0x07);
+ this.vlanID = (short) (tci & 0x0fff);
+ etherType = bb.getShort();
+ } else {
+ this.vlanID = VLAN_UNTAGGED;
+ }
+ this.etherType = etherType;
+
+ IPacket payload;
+ if (Ethernet.etherTypeClassMap.containsKey(this.etherType)) {
+ Class<? extends IPacket> clazz = Ethernet.etherTypeClassMap.get(this.etherType);
+ try {
+ payload = clazz.newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("Error parsing payload for Ethernet packet", e);
+ }
+ } else {
+ payload = new Data();
+ }
+ this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position());
+ this.payload.setParent(this);
+ return this;
+ }
+
+ /**
+ * Checks to see if a string is a valid MAC address.
+ * @param macAddress
+ * @return True if macAddress is a valid MAC, False otherwise
+ */
+ public static boolean isMACAddress(String macAddress) {
+ String[] macBytes = macAddress.split(":");
+ if (macBytes.length != 6)
+ return false;
+ for (int i = 0; i < 6; ++i) {
+ if (HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1 ||
+ HEXES.indexOf(macBytes[i].toUpperCase().charAt(1)) == -1) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
+ * matter, and returns a corresponding byte[].
+ * @param macAddress The MAC address to convert into a bye array
+ * @return The macAddress as a byte array
+ */
+ public static byte[] toMACAddress(String macAddress) {
+ return MACAddress.valueOf(macAddress).toBytes();
+ }
+
+
+ /**
+ * Accepts a MAC address and returns the corresponding long, where the
+ * MAC bytes are set on the lower order bytes of the long.
+ * @param macAddress
+ * @return a long containing the mac address bytes
+ */
+ public static long toLong(byte[] macAddress) {
+ return MACAddress.valueOf(macAddress).toLong();
+ }
+
+ /**
+ * Convert a long MAC address to a byte array
+ * @param macAddress
+ * @return the bytes of the mac address
+ */
+ public static byte[] toByteArray(long macAddress) {
+ return MACAddress.valueOf(macAddress).toBytes();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 7867;
+ int result = super.hashCode();
+ result = prime * result + destinationMACAddress.hashCode();
+ result = prime * result + etherType;
+ result = prime * result + vlanID;
+ result = prime * result + priorityCode;
+ result = prime * result + (pad ? 1231 : 1237);
+ result = prime * result + sourceMACAddress.hashCode();
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof Ethernet))
+ return false;
+ Ethernet other = (Ethernet) obj;
+ if (!destinationMACAddress.equals(other.destinationMACAddress))
+ return false;
+ if (priorityCode != other.priorityCode)
+ return false;
+ if (vlanID != other.vlanID)
+ return false;
+ if (etherType != other.etherType)
+ return false;
+ if (pad != other.pad)
+ return false;
+ if (!sourceMACAddress.equals(other.sourceMACAddress))
+ return false;
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString(java.lang.Object)
+ */
+ @Override
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("\n");
+
+ IPacket pkt = (IPacket) this.getPayload();
+
+ if (pkt instanceof ARP)
+ sb.append("arp");
+ else if (pkt instanceof LLDP)
+ sb.append("lldp");
+ else if (pkt instanceof ICMP)
+ sb.append("icmp");
+ else if (pkt instanceof IPv4)
+ sb.append("ip");
+ else if (pkt instanceof DHCP)
+ sb.append("dhcp");
+ else sb.append(this.getEtherType());
+
+ sb.append("\ndl_vlan: ");
+ if (this.getVlanID() == Ethernet.VLAN_UNTAGGED)
+ sb.append("untagged");
+ else
+ sb.append(this.getVlanID());
+ sb.append("\ndl_vlan_pcp: ");
+ sb.append(this.getPriorityCode());
+ sb.append("\ndl_src: ");
+ sb.append(HexString.toHexString(this.getSourceMACAddress()));
+ sb.append("\ndl_dst: ");
+ sb.append(HexString.toHexString(this.getDestinationMACAddress()));
+
+
+ if (pkt instanceof ARP) {
+ ARP p = (ARP) pkt;
+ sb.append("\nnw_src: ");
+ sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p.getSenderProtocolAddress())));
+ sb.append("\nnw_dst: ");
+ sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p.getTargetProtocolAddress())));
+ }
+ else if (pkt instanceof LLDP) {
+ sb.append("lldp packet");
+ }
+ else if (pkt instanceof ICMP) {
+ ICMP icmp = (ICMP) pkt;
+ sb.append("\nicmp_type: ");
+ sb.append(icmp.getIcmpType());
+ sb.append("\nicmp_code: ");
+ sb.append(icmp.getIcmpCode());
+ }
+ else if (pkt instanceof IPv4) {
+ IPv4 p = (IPv4) pkt;
+ sb.append("\nnw_src: ");
+ sb.append(IPv4.fromIPv4Address(p.getSourceAddress()));
+ sb.append("\nnw_dst: ");
+ sb.append(IPv4.fromIPv4Address(p.getDestinationAddress()));
+ sb.append("\nnw_tos: ");
+ sb.append(p.getDiffServ());
+ sb.append("\nnw_proto: ");
+ sb.append(p.getProtocol());
+
+ if (pkt instanceof TCP) {
+ sb.append("\ntp_src: ");
+ sb.append(((TCP) pkt).getSourcePort());
+ sb.append("\ntp_dst: ");
+ sb.append(((TCP) pkt).getDestinationPort());
+
+ } else if (pkt instanceof UDP) {
+ sb.append("\ntp_src: ");
+ sb.append(((UDP) pkt).getSourcePort());
+ sb.append("\ntp_dst: ");
+ sb.append(((UDP) pkt).getDestinationPort());
+ }
+
+ if (pkt instanceof ICMP) {
+ ICMP icmp = (ICMP) pkt;
+ sb.append("\nicmp_type: ");
+ sb.append(icmp.getIcmpType());
+ sb.append("\nicmp_code: ");
+ sb.append(icmp.getIcmpCode());
+ }
+
+ }
+ else if (pkt instanceof DHCP) {
+ sb.append("\ndhcp packet");
+ }
+ else if (pkt instanceof Data) {
+ sb.append("\ndata packet");
+ }
+ else if (pkt instanceof LLC) {
+ sb.append("\nllc packet");
+ }
+ else if (pkt instanceof BPDU) {
+ sb.append("\nbpdu packet");
+ }
+ else sb.append("\nunknwon packet");
+
+ return sb.toString();
+ }
+
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/ICMP.java b/src/main/java/net/onrc/onos/core/packet/ICMP.java
new file mode 100644
index 0000000..b575878
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/ICMP.java
@@ -0,0 +1,170 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Implements ICMP packet format
+ * @author shudong.zhou@bigswitch.com
+ */
+public class ICMP extends BasePacket {
+ protected byte icmpType;
+ protected byte icmpCode;
+ protected short checksum;
+
+ /**
+ * @return the icmpType
+ */
+ public byte getIcmpType() {
+ return icmpType;
+ }
+
+ /**
+ * @param icmpType to set
+ */
+ public ICMP setIcmpType(byte icmpType) {
+ this.icmpType = icmpType;
+ return this;
+ }
+
+ /**
+ * @return the icmp code
+ */
+ public byte getIcmpCode() {
+ return icmpCode;
+ }
+
+ /**
+ * @param icmpCode code to set
+ */
+ public ICMP setIcmpCode(byte icmpCode) {
+ this.icmpCode = icmpCode;
+ return this;
+ }
+
+ /**
+ * @return the checksum
+ */
+ public short getChecksum() {
+ return checksum;
+ }
+
+ /**
+ * @param checksum the checksum to set
+ */
+ public ICMP setChecksum(short checksum) {
+ this.checksum = checksum;
+ return this;
+ }
+
+ /**
+ * Serializes the packet. Will compute and set the following fields if they
+ * are set to specific values at the time serialize is called:
+ * -checksum : 0
+ * -length : 0
+ */
+ public byte[] serialize() {
+ int length = 4;
+ byte[] payloadData = null;
+ if (payload != null) {
+ payload.setParent(this);
+ payloadData = payload.serialize();
+ length += payloadData.length;
+ }
+
+ byte[] data = new byte[length];
+ ByteBuffer bb = ByteBuffer.wrap(data);
+
+ bb.put(this.icmpType);
+ bb.put(this.icmpCode);
+ bb.putShort(this.checksum);
+ if (payloadData != null)
+ bb.put(payloadData);
+
+ if (this.parent != null && this.parent instanceof IPv4)
+ ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_ICMP);
+
+ // compute checksum if needed
+ if (this.checksum == 0) {
+ bb.rewind();
+ int accumulation = 0;
+
+ for (int i = 0; i < length / 2; ++i) {
+ accumulation += 0xffff & bb.getShort();
+ }
+ // pad to an even number of shorts
+ if (length % 2 > 0) {
+ accumulation += (bb.get() & 0xff) << 8;
+ }
+
+ accumulation = ((accumulation >> 16) & 0xffff)
+ + (accumulation & 0xffff);
+ this.checksum = (short) (~accumulation & 0xffff);
+ bb.putShort(2, this.checksum);
+ }
+ return data;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 5807;
+ int result = super.hashCode();
+ result = prime * result + icmpType;
+ result = prime * result + icmpCode;
+ result = prime * result + checksum;
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof ICMP))
+ return false;
+ ICMP other = (ICMP) obj;
+ if (icmpType != other.icmpType)
+ return false;
+ if (icmpCode != other.icmpCode)
+ return false;
+ if (checksum != other.checksum)
+ return false;
+ return true;
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+ this.icmpType = bb.get();
+ this.icmpCode = bb.get();
+ this.checksum = bb.getShort();
+
+ this.payload = new Data();
+ this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position());
+ this.payload.setParent(this);
+ return this;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/IPacket.java b/src/main/java/net/onrc/onos/core/packet/IPacket.java
new file mode 100644
index 0000000..0cfc51f
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/IPacket.java
@@ -0,0 +1,77 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+/**
+*
+* @author David Erickson (daviderickson@cs.stanford.edu)
+*/
+public interface IPacket {
+ /**
+ *
+ * @return
+ */
+ public IPacket getPayload();
+
+ /**
+ *
+ * @param packet
+ * @return
+ */
+ public IPacket setPayload(IPacket packet);
+
+ /**
+ *
+ * @return
+ */
+ public IPacket getParent();
+
+ /**
+ *
+ * @param packet
+ * @return
+ */
+ public IPacket setParent(IPacket packet);
+
+ /**
+ * Reset any checksums as needed, and call resetChecksum on all parents
+ */
+ public void resetChecksum();
+
+ /**
+ * Sets all payloads parent packet if applicable, then serializes this
+ * packet and all payloads
+ * @return a byte[] containing this packet and payloads
+ */
+ public byte[] serialize();
+
+ /**
+ * Deserializes this packet layer and all possible payloads
+ * @param data
+ * @param offset offset to start deserializing from
+ * @param length length of the data to deserialize
+ * @return the deserialized data
+ */
+ public IPacket deserialize(byte[] data, int offset, int length);
+
+ /** Clone this packet and its payload packet but not its parent.
+ *
+ * @return
+ */
+ public Object clone();
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/IPv4.java b/src/main/java/net/onrc/onos/core/packet/IPv4.java
new file mode 100644
index 0000000..7f9db1a
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/IPv4.java
@@ -0,0 +1,559 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ */
+public class IPv4 extends BasePacket {
+ public static final int ADDRESS_LENGTH = 4;
+ public static final byte PROTOCOL_ICMP = 0x1;
+ public static final byte PROTOCOL_TCP = 0x6;
+ public static final byte PROTOCOL_UDP = 0x11;
+ public static Map<Byte, Class<? extends IPacket>> protocolClassMap;
+
+ static {
+ protocolClassMap = new HashMap<Byte, Class<? extends IPacket>>();
+ protocolClassMap.put(PROTOCOL_ICMP, ICMP.class);
+ protocolClassMap.put(PROTOCOL_TCP, TCP.class);
+ protocolClassMap.put(PROTOCOL_UDP, UDP.class);
+ }
+
+ protected byte version;
+ protected byte headerLength;
+ protected byte diffServ;
+ protected short totalLength;
+ protected short identification;
+ protected byte flags;
+ protected short fragmentOffset;
+ protected byte ttl;
+ protected byte protocol;
+ protected short checksum;
+ protected int sourceAddress;
+ protected int destinationAddress;
+ protected byte[] options;
+
+ protected boolean isTruncated;
+
+ /**
+ * Default constructor that sets the version to 4.
+ */
+ public IPv4() {
+ super();
+ this.version = 4;
+ isTruncated = false;
+ }
+
+ /**
+ * @return the version
+ */
+ public byte getVersion() {
+ return version;
+ }
+
+ /**
+ * @param version the version to set
+ */
+ public IPv4 setVersion(byte version) {
+ this.version = version;
+ return this;
+ }
+
+ /**
+ * @return the headerLength
+ */
+ public byte getHeaderLength() {
+ return headerLength;
+ }
+
+ /**
+ * @return the diffServ
+ */
+ public byte getDiffServ() {
+ return diffServ;
+ }
+
+ /**
+ * @param diffServ the diffServ to set
+ */
+ public IPv4 setDiffServ(byte diffServ) {
+ this.diffServ = diffServ;
+ return this;
+ }
+
+ /**
+ * @return the totalLength
+ */
+ public short getTotalLength() {
+ return totalLength;
+ }
+
+ /**
+ * @return the identification
+ */
+ public short getIdentification() {
+ return identification;
+ }
+
+ public boolean isTruncated() {
+ return isTruncated;
+ }
+
+ public void setTruncated(boolean isTruncated) {
+ this.isTruncated = isTruncated;
+ }
+
+ /**
+ * @param identification the identification to set
+ */
+ public IPv4 setIdentification(short identification) {
+ this.identification = identification;
+ return this;
+ }
+
+ /**
+ * @return the flags
+ */
+ public byte getFlags() {
+ return flags;
+ }
+
+ /**
+ * @param flags the flags to set
+ */
+ public IPv4 setFlags(byte flags) {
+ this.flags = flags;
+ return this;
+ }
+
+ /**
+ * @return the fragmentOffset
+ */
+ public short getFragmentOffset() {
+ return fragmentOffset;
+ }
+
+ /**
+ * @param fragmentOffset the fragmentOffset to set
+ */
+ public IPv4 setFragmentOffset(short fragmentOffset) {
+ this.fragmentOffset = fragmentOffset;
+ return this;
+ }
+
+ /**
+ * @return the ttl
+ */
+ public byte getTtl() {
+ return ttl;
+ }
+
+ /**
+ * @param ttl the ttl to set
+ */
+ public IPv4 setTtl(byte ttl) {
+ this.ttl = ttl;
+ return this;
+ }
+
+ /**
+ * @return the protocol
+ */
+ public byte getProtocol() {
+ return protocol;
+ }
+
+ /**
+ * @param protocol the protocol to set
+ */
+ public IPv4 setProtocol(byte protocol) {
+ this.protocol = protocol;
+ return this;
+ }
+
+ /**
+ * @return the checksum
+ */
+ public short getChecksum() {
+ return checksum;
+ }
+
+ /**
+ * @param checksum the checksum to set
+ */
+ public IPv4 setChecksum(short checksum) {
+ this.checksum = checksum;
+ return this;
+ }
+ @Override
+ public void resetChecksum() {
+ this.checksum = 0;
+ super.resetChecksum();
+ }
+
+ /**
+ * @return the sourceAddress
+ */
+ public int getSourceAddress() {
+ return sourceAddress;
+ }
+
+ /**
+ * @param sourceAddress the sourceAddress to set
+ */
+ public IPv4 setSourceAddress(int sourceAddress) {
+ this.sourceAddress = sourceAddress;
+ return this;
+ }
+
+ /**
+ * @param sourceAddress the sourceAddress to set
+ */
+ public IPv4 setSourceAddress(String sourceAddress) {
+ this.sourceAddress = IPv4.toIPv4Address(sourceAddress);
+ return this;
+ }
+
+ /**
+ * @return the destinationAddress
+ */
+ public int getDestinationAddress() {
+ return destinationAddress;
+ }
+
+ /**
+ * @param destinationAddress the destinationAddress to set
+ */
+ public IPv4 setDestinationAddress(int destinationAddress) {
+ this.destinationAddress = destinationAddress;
+ return this;
+ }
+
+ /**
+ * @param destinationAddress the destinationAddress to set
+ */
+ public IPv4 setDestinationAddress(String destinationAddress) {
+ this.destinationAddress = IPv4.toIPv4Address(destinationAddress);
+ return this;
+ }
+
+ /**
+ * @return the options
+ */
+ public byte[] getOptions() {
+ return options;
+ }
+
+ /**
+ * @param options the options to set
+ */
+ public IPv4 setOptions(byte[] options) {
+ if (options != null && (options.length % 4) > 0)
+ throw new IllegalArgumentException(
+ "Options length must be a multiple of 4");
+ this.options = options;
+ return this;
+ }
+
+ /**
+ * Serializes the packet. Will compute and set the following fields if they
+ * are set to specific values at the time serialize is called:
+ * -checksum : 0
+ * -headerLength : 0
+ * -totalLength : 0
+ */
+ public byte[] serialize() {
+ byte[] payloadData = null;
+ if (payload != null) {
+ payload.setParent(this);
+ payloadData = payload.serialize();
+ }
+
+ int optionsLength = 0;
+ if (this.options != null)
+ optionsLength = this.options.length / 4;
+ this.headerLength = (byte) (5 + optionsLength);
+
+ this.totalLength = (short) (this.headerLength * 4 + ((payloadData == null) ? 0
+ : payloadData.length));
+
+ byte[] data = new byte[this.totalLength];
+ ByteBuffer bb = ByteBuffer.wrap(data);
+
+ bb.put((byte) (((this.version & 0xf) << 4) | (this.headerLength & 0xf)));
+ bb.put(this.diffServ);
+ bb.putShort(this.totalLength);
+ bb.putShort(this.identification);
+ bb.putShort((short) (((this.flags & 0x7) << 13) | (this.fragmentOffset & 0x1fff)));
+ bb.put(this.ttl);
+ bb.put(this.protocol);
+ bb.putShort(this.checksum);
+ bb.putInt(this.sourceAddress);
+ bb.putInt(this.destinationAddress);
+ if (this.options != null)
+ bb.put(this.options);
+ if (payloadData != null)
+ bb.put(payloadData);
+
+ // compute checksum if needed
+ if (this.checksum == 0) {
+ bb.rewind();
+ int accumulation = 0;
+ for (int i = 0; i < this.headerLength * 2; ++i) {
+ accumulation += 0xffff & bb.getShort();
+ }
+ accumulation = ((accumulation >> 16) & 0xffff)
+ + (accumulation & 0xffff);
+ this.checksum = (short) (~accumulation & 0xffff);
+ bb.putShort(10, this.checksum);
+ }
+ return data;
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+ short sscratch;
+
+ this.version = bb.get();
+ this.headerLength = (byte) (this.version & 0xf);
+ this.version = (byte) ((this.version >> 4) & 0xf);
+ this.diffServ = bb.get();
+ this.totalLength = bb.getShort();
+ this.identification = bb.getShort();
+ sscratch = bb.getShort();
+ this.flags = (byte) ((sscratch >> 13) & 0x7);
+ this.fragmentOffset = (short) (sscratch & 0x1fff);
+ this.ttl = bb.get();
+ this.protocol = bb.get();
+ this.checksum = bb.getShort();
+ this.sourceAddress = bb.getInt();
+ this.destinationAddress = bb.getInt();
+
+ if (this.headerLength > 5) {
+ int optionsLength = (this.headerLength - 5) * 4;
+ this.options = new byte[optionsLength];
+ bb.get(this.options);
+ }
+
+ IPacket payload;
+ if (IPv4.protocolClassMap.containsKey(this.protocol)) {
+ Class<? extends IPacket> clazz = IPv4.protocolClassMap.get(this.protocol);
+ try {
+ payload = clazz.newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("Error parsing payload for IPv4 packet", e);
+ }
+ } else {
+ payload = new Data();
+ }
+ this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position());
+ this.payload.setParent(this);
+
+ if (this.totalLength != length)
+ this.isTruncated = true;
+ else
+ this.isTruncated = false;
+
+ return this;
+ }
+
+ /**
+ * Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and
+ * returns the corresponding 32 bit integer.
+ * @param ipAddress
+ * @return
+ */
+ public static int toIPv4Address(String ipAddress) {
+ if (ipAddress == null)
+ throw new IllegalArgumentException("Specified IPv4 address must" +
+ "contain 4 sets of numerical digits separated by periods");
+ String[] octets = ipAddress.split("\\.");
+ if (octets.length != 4)
+ throw new IllegalArgumentException("Specified IPv4 address must" +
+ "contain 4 sets of numerical digits separated by periods");
+
+ int result = 0;
+ for (int i = 0; i < 4; ++i) {
+ result |= Integer.valueOf(octets[i]) << ((3-i)*8);
+ }
+ return result;
+ }
+
+ /**
+ * Accepts an IPv4 address in a byte array and returns the corresponding
+ * 32-bit integer value.
+ * @param ipAddress
+ * @return
+ */
+ public static int toIPv4Address(byte[] ipAddress) {
+ int ip = 0;
+ for (int i = 0; i < 4; i++) {
+ int t = (ipAddress[i] & 0xff) << ((3-i)*8);
+ ip |= t;
+ }
+ return ip;
+ }
+
+ /**
+ * Accepts an IPv4 address and returns of string of the form xxx.xxx.xxx.xxx
+ * ie 192.168.0.1
+ *
+ * @param ipAddress
+ * @return
+ */
+ public static String fromIPv4Address(int ipAddress) {
+ StringBuffer sb = new StringBuffer();
+ int result = 0;
+ for (int i = 0; i < 4; ++i) {
+ result = (ipAddress >> ((3-i)*8)) & 0xff;
+ sb.append(Integer.valueOf(result).toString());
+ if (i != 3)
+ sb.append(".");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Accepts a collection of IPv4 addresses as integers and returns a single
+ * String useful in toString method's containing collections of IP
+ * addresses.
+ *
+ * @param ipAddresses collection
+ * @return
+ */
+ public static String fromIPv4AddressCollection(Collection<Integer> ipAddresses) {
+ if (ipAddresses == null)
+ return "null";
+ StringBuffer sb = new StringBuffer();
+ sb.append("[");
+ for (Integer ip : ipAddresses) {
+ sb.append(fromIPv4Address(ip));
+ sb.append(",");
+ }
+ sb.replace(sb.length()-1, sb.length(), "]");
+ return sb.toString();
+ }
+
+ /**
+ * Accepts an IPv4 address of the form xxx.xxx.xxx.xxx, ie 192.168.0.1 and
+ * returns the corresponding byte array.
+ * @param ipAddress The IP address in the form xx.xxx.xxx.xxx.
+ * @return The IP address separated into bytes
+ */
+ public static byte[] toIPv4AddressBytes(String ipAddress) {
+ String[] octets = ipAddress.split("\\.");
+ if (octets.length != 4)
+ throw new IllegalArgumentException("Specified IPv4 address must" +
+ "contain 4 sets of numerical digits separated by periods");
+
+ byte[] result = new byte[4];
+ for (int i = 0; i < 4; ++i) {
+ result[i] = Integer.valueOf(octets[i]).byteValue();
+ }
+ return result;
+ }
+
+ /**
+ * Accepts an IPv4 address in the form of an integer and
+ * returns the corresponding byte array.
+ * @param ipAddress The IP address as an integer.
+ * @return The IP address separated into bytes.
+ */
+ public static byte[] toIPv4AddressBytes(int ipAddress) {
+ return new byte[] {
+ (byte)(ipAddress >>> 24),
+ (byte)(ipAddress >>> 16),
+ (byte)(ipAddress >>> 8),
+ (byte)ipAddress};
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 2521;
+ int result = super.hashCode();
+ result = prime * result + checksum;
+ result = prime * result + destinationAddress;
+ result = prime * result + diffServ;
+ result = prime * result + flags;
+ result = prime * result + fragmentOffset;
+ result = prime * result + headerLength;
+ result = prime * result + identification;
+ result = prime * result + Arrays.hashCode(options);
+ result = prime * result + protocol;
+ result = prime * result + sourceAddress;
+ result = prime * result + totalLength;
+ result = prime * result + ttl;
+ result = prime * result + version;
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof IPv4))
+ return false;
+ IPv4 other = (IPv4) obj;
+ if (checksum != other.checksum)
+ return false;
+ if (destinationAddress != other.destinationAddress)
+ return false;
+ if (diffServ != other.diffServ)
+ return false;
+ if (flags != other.flags)
+ return false;
+ if (fragmentOffset != other.fragmentOffset)
+ return false;
+ if (headerLength != other.headerLength)
+ return false;
+ if (identification != other.identification)
+ return false;
+ if (!Arrays.equals(options, other.options))
+ return false;
+ if (protocol != other.protocol)
+ return false;
+ if (sourceAddress != other.sourceAddress)
+ return false;
+ if (totalLength != other.totalLength)
+ return false;
+ if (ttl != other.ttl)
+ return false;
+ if (version != other.version)
+ return false;
+ return true;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/LLC.java b/src/main/java/net/onrc/onos/core/packet/LLC.java
new file mode 100644
index 0000000..c4f0c27
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/LLC.java
@@ -0,0 +1,75 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+
+/**
+ * This class represents an Link Local Control
+ * header that is used in Ethernet 802.3.
+ * @author alexreimers
+ *
+ */
+public class LLC extends BasePacket {
+ private byte dsap = 0;
+ private byte ssap = 0;
+ private byte ctrl = 0;
+
+ public byte getDsap() {
+ return dsap;
+ }
+
+ public void setDsap(byte dsap) {
+ this.dsap = dsap;
+ }
+
+ public byte getSsap() {
+ return ssap;
+ }
+
+ public void setSsap(byte ssap) {
+ this.ssap = ssap;
+ }
+
+ public byte getCtrl() {
+ return ctrl;
+ }
+
+ public void setCtrl(byte ctrl) {
+ this.ctrl = ctrl;
+ }
+
+ @Override
+ public byte[] serialize() {
+ byte[] data = new byte[3];
+ ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.put(dsap);
+ bb.put(ssap);
+ bb.put(ctrl);
+ return data;
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+ dsap = bb.get();
+ ssap = bb.get();
+ ctrl = bb.get();
+ return this;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/LLDP.java b/src/main/java/net/onrc/onos/core/packet/LLDP.java
new file mode 100644
index 0000000..307a052
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/LLDP.java
@@ -0,0 +1,204 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ *
+ */
+public class LLDP extends BasePacket {
+ protected LLDPTLV chassisId;
+ protected LLDPTLV portId;
+ protected LLDPTLV ttl;
+ protected List<LLDPTLV> optionalTLVList;
+ protected short ethType;
+
+ public LLDP() {
+ this.optionalTLVList = new ArrayList<LLDPTLV>();
+ this.ethType = Ethernet.TYPE_LLDP;
+ }
+
+ /**
+ * @return the chassisId
+ */
+ public LLDPTLV getChassisId() {
+ return chassisId;
+ }
+
+ /**
+ * @param chassisId the chassisId to set
+ */
+ public LLDP setChassisId(LLDPTLV chassisId) {
+ this.chassisId = chassisId;
+ return this;
+ }
+
+ /**
+ * @return the portId
+ */
+ public LLDPTLV getPortId() {
+ return portId;
+ }
+
+ /**
+ * @param portId the portId to set
+ */
+ public LLDP setPortId(LLDPTLV portId) {
+ this.portId = portId;
+ return this;
+ }
+
+ /**
+ * @return the ttl
+ */
+ public LLDPTLV getTtl() {
+ return ttl;
+ }
+
+ /**
+ * @param ttl the ttl to set
+ */
+ public LLDP setTtl(LLDPTLV ttl) {
+ this.ttl = ttl;
+ return this;
+ }
+
+ /**
+ * @return the optionalTLVList
+ */
+ public List<LLDPTLV> getOptionalTLVList() {
+ return optionalTLVList;
+ }
+
+ /**
+ * @param optionalTLVList the optionalTLVList to set
+ */
+ public LLDP setOptionalTLVList(List<LLDPTLV> optionalTLVList) {
+ this.optionalTLVList = optionalTLVList;
+ return this;
+ }
+
+ @Override
+ public byte[] serialize() {
+ int length = 2+this.chassisId.getLength() + 2+this.portId.getLength() +
+ 2+this.ttl.getLength() + 2;
+ for (LLDPTLV tlv : this.optionalTLVList) {
+ length += 2 + tlv.getLength();
+ }
+
+ byte[] data = new byte[length];
+ ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.put(this.chassisId.serialize());
+ bb.put(this.portId.serialize());
+ bb.put(this.ttl.serialize());
+ for (LLDPTLV tlv : this.optionalTLVList) {
+ bb.put(tlv.serialize());
+ }
+ bb.putShort((short) 0); // End of LLDPDU
+
+ if (this.parent != null && this.parent instanceof Ethernet)
+ ((Ethernet)this.parent).setEtherType(ethType);
+
+ return data;
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+ LLDPTLV tlv;
+ do {
+ tlv = new LLDPTLV().deserialize(bb);
+
+ // if there was a failure to deserialize stop processing TLVs
+ if (tlv == null)
+ break;
+ switch (tlv.getType()) {
+ case 0x0:
+ // can throw this one away, its just an end delimiter
+ break;
+ case 0x1:
+ this.chassisId = tlv;
+ break;
+ case 0x2:
+ this.portId = tlv;
+ break;
+ case 0x3:
+ this.ttl = tlv;
+ break;
+ default:
+ this.optionalTLVList.add(tlv);
+ break;
+ }
+ } while (tlv.getType() != 0 && bb.hasRemaining());
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 883;
+ int result = super.hashCode();
+ result = prime * result
+ + ((chassisId == null) ? 0 : chassisId.hashCode());
+ result = prime * result + (optionalTLVList.hashCode());
+ result = prime * result + ((portId == null) ? 0 : portId.hashCode());
+ result = prime * result + ((ttl == null) ? 0 : ttl.hashCode());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof LLDP))
+ return false;
+ LLDP other = (LLDP) obj;
+ if (chassisId == null) {
+ if (other.chassisId != null)
+ return false;
+ } else if (!chassisId.equals(other.chassisId))
+ return false;
+ if (!optionalTLVList.equals(other.optionalTLVList))
+ return false;
+ if (portId == null) {
+ if (other.portId != null)
+ return false;
+ } else if (!portId.equals(other.portId))
+ return false;
+ if (ttl == null) {
+ if (other.ttl != null)
+ return false;
+ } else if (!ttl.equals(other.ttl))
+ return false;
+ return true;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/LLDPOrganizationalTLV.java b/src/main/java/net/onrc/onos/core/packet/LLDPOrganizationalTLV.java
new file mode 100644
index 0000000..f3cd655
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/LLDPOrganizationalTLV.java
@@ -0,0 +1,181 @@
+/**
+ * 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+/**
+ * The class representing LLDP Organizationally Specific TLV.
+ *
+ * @author Sho Shimizu (sho.shimizu@gmail.com)
+ */
+public class LLDPOrganizationalTLV extends LLDPTLV {
+ public static final int OUI_LENGTH = 3;
+ public static final int SUBTYPE_LENGTH = 1;
+ public static final byte ORGANIZATIONAL_TLV_TYPE = 127;
+ public static final int MAX_INFOSTRING_LENGTH = 507;
+
+ protected byte[] oui;
+ protected byte subType;
+ private byte[] infoString;
+
+ public LLDPOrganizationalTLV() {
+ type = ORGANIZATIONAL_TLV_TYPE;
+ }
+
+ /**
+ * Set the value of OUI.
+ * @param oui The value of OUI to be set.
+ * @return This LLDP Organizationally Specific TLV.
+ */
+ public LLDPOrganizationalTLV setOUI(byte[] oui) {
+ if (oui.length != OUI_LENGTH) {
+ throw new IllegalArgumentException("The length of OUI must be " + OUI_LENGTH +
+ ", but it is " + oui.length);
+ }
+ this.oui = Arrays.copyOf(oui, oui.length);
+ return this;
+ }
+
+ /**
+ * Returns the value of the OUI.
+ * @return The value of the OUI .
+ */
+ public byte[] getOUI() {
+ return Arrays.copyOf(oui, oui.length);
+ }
+
+ /**
+ * Set the value of sub type.
+ * @param subType The value of sub type to be set.
+ * @return This LLDP Organizationally Specific TLV.
+ */
+ public LLDPOrganizationalTLV setSubType(byte subType) {
+ this.subType = subType;
+ return this;
+ }
+
+ /**
+ * Returns the value of the sub type.
+ * @return The value of the sub type.
+ */
+ public byte getSubType() {
+ return subType;
+ }
+
+ /**
+ * Set the value of information string.
+ * @param infoString the byte array of the value of information string.
+ * @return This LLDP Organizationally Specific TLV.
+ */
+ public LLDPOrganizationalTLV setInfoString(byte[] infoString) {
+ if (infoString.length > MAX_INFOSTRING_LENGTH) {
+ throw new IllegalArgumentException("The length of infoString cannot exceed " + MAX_INFOSTRING_LENGTH);
+ }
+ this.infoString = Arrays.copyOf(infoString, infoString.length);
+ return this;
+ }
+
+ /**
+ * Set the value of information string.
+ * The String value is automatically converted into byte array with UTF-8 encoding.
+ * @param infoString the String value of information string.
+ * @return This LLDP Organizationally Specific TLV.
+ */
+ public LLDPOrganizationalTLV setInfoString(String infoString) {
+ byte[] infoStringBytes = infoString.getBytes(Charset.forName("UTF-8"));
+ return setInfoString(infoStringBytes);
+ }
+
+ /**
+ * Returns the value of information string.
+ * @return the value of information string.
+ */
+ public byte[] getInfoString() {
+ return Arrays.copyOf(infoString, infoString.length);
+ }
+
+ @Override
+ public byte[] serialize() {
+ int valueLength = OUI_LENGTH + SUBTYPE_LENGTH + infoString.length;
+ value = new byte[valueLength];
+ ByteBuffer bb = ByteBuffer.wrap(value);
+ bb.put(oui);
+ bb.put(subType);
+ bb.put(infoString);
+ return super.serialize();
+ }
+
+ @Override
+ public LLDPTLV deserialize(ByteBuffer bb) {
+ super.deserialize(bb);
+ ByteBuffer optionalField = ByteBuffer.wrap(value);
+
+ byte[] oui = new byte[OUI_LENGTH];
+ optionalField.get(oui);
+ setOUI(oui);
+
+ setSubType(optionalField.get());
+
+ byte[] infoString = new byte[getLength() - OUI_LENGTH - SUBTYPE_LENGTH];
+ optionalField.get(infoString);
+ setInfoString(infoString);
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 1423;
+ int result = 1;
+ result = prime * result + type;
+ result = prime * result + length;
+ result = prime * result + Arrays.hashCode(oui);
+ result = prime * result + subType;
+ result = prime * result + Arrays.hashCode(infoString);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (!(o instanceof LLDPOrganizationalTLV)) {
+ return false;
+ }
+
+ LLDPOrganizationalTLV other = (LLDPOrganizationalTLV)o;
+ if (this.type != other.type) {
+ return false;
+ }
+ if (this.length != other.length) {
+ return false;
+ }
+ if (!Arrays.equals(this.oui, other.oui)) {
+ return false;
+ }
+ if (this.subType != other.subType) {
+ return false;
+ }
+ if (!Arrays.equals(this.infoString, other.infoString)) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/LLDPTLV.java b/src/main/java/net/onrc/onos/core/packet/LLDPTLV.java
new file mode 100644
index 0000000..d7bcc68
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/LLDPTLV.java
@@ -0,0 +1,140 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+/**
+ *
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class LLDPTLV {
+ protected byte type;
+ protected short length;
+ protected byte[] value;
+
+ /**
+ * @return the type
+ */
+ public byte getType() {
+ return type;
+ }
+
+ /**
+ * @param type the type to set
+ */
+ public LLDPTLV setType(byte type) {
+ this.type = type;
+ return this;
+ }
+
+ /**
+ * @return the length
+ */
+ public short getLength() {
+ return length;
+ }
+
+ /**
+ * @param length the length to set
+ */
+ public LLDPTLV setLength(short length) {
+ this.length = length;
+ return this;
+ }
+
+ /**
+ * @return the value
+ */
+ public byte[] getValue() {
+ return value;
+ }
+
+ /**
+ * @param value the value to set
+ */
+ public LLDPTLV setValue(byte[] value) {
+ this.value = value;
+ return this;
+ }
+
+ public byte[] serialize() {
+ // type = 7 bits
+ // info string length 9 bits, each value == byte
+ // info string
+ short scratch = (short) (((0x7f & this.type) << 9) | (0x1ff & this.length));
+ byte[] data = new byte[2+this.length];
+ ByteBuffer bb = ByteBuffer.wrap(data);
+ bb.putShort(scratch);
+ if (this.value != null)
+ bb.put(this.value);
+ return data;
+ }
+
+ public LLDPTLV deserialize(ByteBuffer bb) {
+ short sscratch;
+ sscratch = bb.getShort();
+ this.type = (byte) ((sscratch >> 9) & 0x7f);
+ this.length = (short) (sscratch & 0x1ff);
+ if (this.length > 0) {
+ this.value = new byte[this.length];
+
+ // if there is an underrun just toss the TLV
+ if (bb.remaining() < this.length)
+ return null;
+ bb.get(this.value);
+ }
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 1423;
+ int result = 1;
+ result = prime * result + length;
+ result = prime * result + type;
+ result = prime * result + Arrays.hashCode(value);
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof LLDPTLV))
+ return false;
+ LLDPTLV other = (LLDPTLV) obj;
+ if (length != other.length)
+ return false;
+ if (type != other.type)
+ return false;
+ if (!Arrays.equals(value, other.value))
+ return false;
+ return true;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/TCP.java b/src/main/java/net/onrc/onos/core/packet/TCP.java
new file mode 100644
index 0000000..7eb78bd
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/TCP.java
@@ -0,0 +1,290 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @author shudong.zhou@bigswitch.com
+ */
+public class TCP extends BasePacket {
+ protected short sourcePort;
+ protected short destinationPort;
+ protected int sequence;
+ protected int acknowledge;
+ protected byte dataOffset;
+ protected short flags;
+ protected short windowSize;
+ protected short checksum;
+ protected short urgentPointer;
+ protected byte[] options;
+
+ /**
+ * @return the sourcePort
+ */
+ public short getSourcePort() {
+ return sourcePort;
+ }
+
+ /**
+ * @param sourcePort the sourcePort to set
+ */
+ public TCP setSourcePort(short sourcePort) {
+ this.sourcePort = sourcePort;
+ return this;
+ }
+
+ /**
+ * @return the destinationPort
+ */
+ public short getDestinationPort() {
+ return destinationPort;
+ }
+
+ /**
+ * @param destinationPort the destinationPort to set
+ */
+ public TCP setDestinationPort(short destinationPort) {
+ this.destinationPort = destinationPort;
+ return this;
+ }
+
+ /**
+ * @return the checksum
+ */
+ public short getChecksum() {
+ return checksum;
+ }
+
+ public int getSequence() {
+ return this.sequence;
+ }
+ public TCP setSequence(int seq) {
+ this.sequence = seq;
+ return this;
+ }
+ public int getAcknowledge() {
+ return this.acknowledge;
+ }
+ public TCP setAcknowledge(int ack) {
+ this.acknowledge = ack;
+ return this;
+ }
+ public byte getDataOffset() {
+ return this.dataOffset;
+ }
+ public TCP setDataOffset(byte offset) {
+ this.dataOffset = offset;
+ return this;
+ }
+ public short getFlags() {
+ return this.flags;
+ }
+ public TCP setFlags(short flags) {
+ this.flags = flags;
+ return this;
+ }
+ public short getWindowSize() {
+ return this.windowSize;
+ }
+ public TCP setWindowSize(short windowSize) {
+ this.windowSize = windowSize;
+ return this;
+ }
+ public short getTcpChecksum() {
+ return this.checksum;
+ }
+ public TCP setTcpChecksum(short checksum) {
+ this.checksum = checksum;
+ return this;
+ }
+
+ @Override
+ public void resetChecksum() {
+ this.checksum = 0;
+ super.resetChecksum();
+ }
+
+ public short getUrgentPointer(short urgentPointer) {
+ return this.urgentPointer;
+ }
+ public TCP setUrgentPointer(short urgentPointer) {
+ this.urgentPointer= urgentPointer;
+ return this;
+ }
+ public byte[] getOptions() {
+ return this.options;
+ }
+ public TCP setOptions(byte[] options) {
+ this.options = options;
+ this.dataOffset = (byte) ((20 + options.length + 3) >> 2);
+ return this;
+ }
+ /**
+ * @param checksum the checksum to set
+ */
+ public TCP setChecksum(short checksum) {
+ this.checksum = checksum;
+ return this;
+ }
+
+ /**
+ * Serializes the packet. Will compute and set the following fields if they
+ * are set to specific values at the time serialize is called:
+ * -checksum : 0
+ * -length : 0
+ */
+ public byte[] serialize() {
+ int length;
+ if (dataOffset == 0)
+ dataOffset = 5; // default header length
+ length = dataOffset << 2;
+ byte[] payloadData = null;
+ if (payload != null) {
+ payload.setParent(this);
+ payloadData = payload.serialize();
+ length += payloadData.length;
+ }
+
+ byte[] data = new byte[length];
+ ByteBuffer bb = ByteBuffer.wrap(data);
+
+ bb.putShort(this.sourcePort);
+ bb.putShort(this.destinationPort);
+ bb.putInt(this.sequence);
+ bb.putInt(this.acknowledge);
+ bb.putShort((short) (this.flags | (dataOffset << 12)));
+ bb.putShort(this.windowSize);
+ bb.putShort(this.checksum);
+ bb.putShort(this.urgentPointer);
+ if (dataOffset > 5) {
+ int padding;
+ bb.put(options);
+ padding = (dataOffset << 2) - 20 - options.length;
+ for (int i = 0; i < padding; i++)
+ bb.put((byte) 0);
+ }
+ if (payloadData != null)
+ bb.put(payloadData);
+
+ if (this.parent != null && this.parent instanceof IPv4)
+ ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_TCP);
+
+ // compute checksum if needed
+ if (this.checksum == 0) {
+ bb.rewind();
+ int accumulation = 0;
+
+ // compute pseudo header mac
+ if (this.parent != null && this.parent instanceof IPv4) {
+ IPv4 ipv4 = (IPv4) this.parent;
+ accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff)
+ + (ipv4.getSourceAddress() & 0xffff);
+ accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff)
+ + (ipv4.getDestinationAddress() & 0xffff);
+ accumulation += ipv4.getProtocol() & 0xff;
+ accumulation += length & 0xffff;
+ }
+
+ for (int i = 0; i < length / 2; ++i) {
+ accumulation += 0xffff & bb.getShort();
+ }
+ // pad to an even number of shorts
+ if (length % 2 > 0) {
+ accumulation += (bb.get() & 0xff) << 8;
+ }
+
+ accumulation = ((accumulation >> 16) & 0xffff)
+ + (accumulation & 0xffff);
+ this.checksum = (short) (~accumulation & 0xffff);
+ bb.putShort(16, this.checksum);
+ }
+ return data;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 5807;
+ int result = super.hashCode();
+ result = prime * result + checksum;
+ result = prime * result + destinationPort;
+ result = prime * result + sourcePort;
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof TCP))
+ return false;
+ TCP other = (TCP) obj;
+ // May want to compare fields based on the flags set
+ return (checksum == other.checksum) &&
+ (destinationPort == other.destinationPort) &&
+ (sourcePort == other.sourcePort) &&
+ (sequence == other.sequence) &&
+ (acknowledge == other.acknowledge) &&
+ (dataOffset == other.dataOffset) &&
+ (flags == other.flags) &&
+ (windowSize == other.windowSize) &&
+ (urgentPointer == other.urgentPointer) &&
+ (dataOffset == 5 || options.equals(other.options));
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+ this.sourcePort = bb.getShort();
+ this.destinationPort = bb.getShort();
+ this.sequence = bb.getInt();
+ this.acknowledge = bb.getInt();
+ this.flags = bb.getShort();
+ this.dataOffset = (byte) ((this.flags >> 12) & 0xf);
+ this.flags = (short) (this.flags & 0x1ff);
+ this.windowSize = bb.getShort();
+ this.checksum = bb.getShort();
+ this.urgentPointer = bb.getShort();
+ if (this.dataOffset > 5) {
+ int optLength = (dataOffset << 2) - 20;
+ if (bb.limit() < bb.position()+optLength) {
+ optLength = bb.limit() - bb.position();
+ }
+ try {
+ this.options = new byte[optLength];
+ bb.get(this.options, 0, optLength);
+ } catch (IndexOutOfBoundsException e) {
+ this.options = null;
+ }
+ }
+
+ this.payload = new Data();
+ this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position());
+ this.payload.setParent(this);
+ return this;
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/packet/UDP.java b/src/main/java/net/onrc/onos/core/packet/UDP.java
new file mode 100644
index 0000000..950afaf
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/packet/UDP.java
@@ -0,0 +1,231 @@
+/**
+* Copyright 2011, Big Switch Networks, Inc.
+* Originally created by David Erickson, Stanford University
+*
+* 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 net.onrc.onos.core.packet;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ */
+public class UDP extends BasePacket {
+ public static Map<Short, Class<? extends IPacket>> decodeMap;
+ public static short DHCP_SERVER_PORT = (short)67;
+ public static short DHCP_CLIENT_PORT = (short)68;
+
+ static {
+ decodeMap = new HashMap<Short, Class<? extends IPacket>>();
+ /*
+ * Disable DHCP until the deserialize code is hardened to deal with garbage input
+ */
+ UDP.decodeMap.put(DHCP_SERVER_PORT, DHCP.class);
+ UDP.decodeMap.put(DHCP_CLIENT_PORT, DHCP.class);
+
+ }
+
+ protected short sourcePort;
+ protected short destinationPort;
+ protected short length;
+ protected short checksum;
+
+ /**
+ * @return the sourcePort
+ */
+ public short getSourcePort() {
+ return sourcePort;
+ }
+
+ /**
+ * @param sourcePort the sourcePort to set
+ */
+ public UDP setSourcePort(short sourcePort) {
+ this.sourcePort = sourcePort;
+ return this;
+ }
+
+ /**
+ * @return the destinationPort
+ */
+ public short getDestinationPort() {
+ return destinationPort;
+ }
+
+ /**
+ * @param destinationPort the destinationPort to set
+ */
+ public UDP setDestinationPort(short destinationPort) {
+ this.destinationPort = destinationPort;
+ return this;
+ }
+
+ /**
+ * @return the length
+ */
+ public short getLength() {
+ return length;
+ }
+
+ /**
+ * @return the checksum
+ */
+ public short getChecksum() {
+ return checksum;
+ }
+
+ /**
+ * @param checksum the checksum to set
+ */
+ public UDP setChecksum(short checksum) {
+ this.checksum = checksum;
+ return this;
+ }
+
+ @Override
+ public void resetChecksum() {
+ this.checksum = 0;
+ super.resetChecksum();
+ }
+
+ /**
+ * Serializes the packet. Will compute and set the following fields if they
+ * are set to specific values at the time serialize is called:
+ * -checksum : 0
+ * -length : 0
+ */
+ public byte[] serialize() {
+ byte[] payloadData = null;
+ if (payload != null) {
+ payload.setParent(this);
+ payloadData = payload.serialize();
+ }
+
+ this.length = (short) (8 + ((payloadData == null) ? 0
+ : payloadData.length));
+
+ byte[] data = new byte[this.length];
+ ByteBuffer bb = ByteBuffer.wrap(data);
+
+ bb.putShort(this.sourcePort);
+ bb.putShort(this.destinationPort);
+ bb.putShort(this.length);
+ bb.putShort(this.checksum);
+ if (payloadData != null)
+ bb.put(payloadData);
+
+ if (this.parent != null && this.parent instanceof IPv4)
+ ((IPv4)this.parent).setProtocol(IPv4.PROTOCOL_UDP);
+
+ // compute checksum if needed
+ if (this.checksum == 0) {
+ bb.rewind();
+ int accumulation = 0;
+
+ // compute pseudo header mac
+ if (this.parent != null && this.parent instanceof IPv4) {
+ IPv4 ipv4 = (IPv4) this.parent;
+ accumulation += ((ipv4.getSourceAddress() >> 16) & 0xffff)
+ + (ipv4.getSourceAddress() & 0xffff);
+ accumulation += ((ipv4.getDestinationAddress() >> 16) & 0xffff)
+ + (ipv4.getDestinationAddress() & 0xffff);
+ accumulation += ipv4.getProtocol() & 0xff;
+ accumulation += this.length & 0xffff;
+ }
+
+ for (int i = 0; i < this.length / 2; ++i) {
+ accumulation += 0xffff & bb.getShort();
+ }
+ // pad to an even number of shorts
+ if (this.length % 2 > 0) {
+ accumulation += (bb.get() & 0xff) << 8;
+ }
+
+ accumulation = ((accumulation >> 16) & 0xffff)
+ + (accumulation & 0xffff);
+ this.checksum = (short) (~accumulation & 0xffff);
+ bb.putShort(6, this.checksum);
+ }
+ return data;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 5807;
+ int result = super.hashCode();
+ result = prime * result + checksum;
+ result = prime * result + destinationPort;
+ result = prime * result + length;
+ result = prime * result + sourcePort;
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (!(obj instanceof UDP))
+ return false;
+ UDP other = (UDP) obj;
+ if (checksum != other.checksum)
+ return false;
+ if (destinationPort != other.destinationPort)
+ return false;
+ if (length != other.length)
+ return false;
+ if (sourcePort != other.sourcePort)
+ return false;
+ return true;
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+ this.sourcePort = bb.getShort();
+ this.destinationPort = bb.getShort();
+ this.length = bb.getShort();
+ this.checksum = bb.getShort();
+
+ if (UDP.decodeMap.containsKey(this.destinationPort)) {
+ try {
+ this.payload = UDP.decodeMap.get(this.destinationPort).getConstructor().newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("Failure instantiating class", e);
+ }
+ } else if (UDP.decodeMap.containsKey(this.sourcePort)) {
+ try {
+ this.payload = UDP.decodeMap.get(this.sourcePort).getConstructor().newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("Failure instantiating class", e);
+ }
+ } else {
+ this.payload = new Data();
+ }
+ this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position());
+ this.payload.setParent(this);
+ return this;
+ }
+}