[CORD-1664] Fix errors when parsing DHCP packets

Change-Id: Ifa9cd3ba04b31f2b7de60fd63dc655978042dbce
diff --git a/utils/misc/src/main/java/org/onlab/packet/DHCP6.java b/utils/misc/src/main/java/org/onlab/packet/DHCP6.java
index fe6debd..924d181 100644
--- a/utils/misc/src/main/java/org/onlab/packet/DHCP6.java
+++ b/utils/misc/src/main/java/org/onlab/packet/DHCP6.java
@@ -39,6 +39,7 @@
  * Base on RFC-3315.
  */
 public class DHCP6 extends BasePacket {
+    private static final int UNSIGNED_SHORT_MASK = 0xffff;
     // size of different field of option
     private static final int OPT_CODE_SIZE = 2;
     private static final int OPT_LEN_SIZE = 2;
@@ -87,7 +88,7 @@
         RELAY_MSG((short) 9), AUTH((short) 11), UNICAST((short) 12),
         STATUS_CODE((short) 13), RAPID_COMMIT((short) 14), USER_CLASS((short) 15),
         VENDOR_CLASS((short) 16), VENDOR_OPTS((short) 17), INTERFACE_ID((short) 18),
-        RECONF_MSG((short) 19), RECONF_ACCEPT((short) 20);
+        RECONF_MSG((short) 19), RECONF_ACCEPT((short) 20), SUBSCRIBER_ID((short) 38);
 
         protected short value;
         OptionCode(final short value) {
@@ -183,7 +184,7 @@
             }
 
             // peek message type
-            dhcp6.msgType = (byte) (0xff & bb.array()[offset]);
+            dhcp6.msgType = bb.array()[offset];
             if (RELAY_MSG_TYPES.contains(dhcp6.msgType)) {
                 bb.get(); // drop message type
                 dhcp6.hopCount = bb.get();
@@ -202,9 +203,9 @@
             while (bb.remaining() >= Dhcp6Option.DEFAULT_LEN) {
                 // create temporary byte buffer for reading code and length
                 ByteBuffer optByteBuffer =
-                        ByteBuffer.wrap(data, bb.position(), length - bb.position());
+                        ByteBuffer.wrap(data, bb.position(), bb.limit() - bb.position());
                 short code = optByteBuffer.getShort();
-                short optionLen = (short) (0xffff & optByteBuffer.getShort());
+                int optionLen = UNSIGNED_SHORT_MASK & optByteBuffer.getShort();
                 if (optByteBuffer.remaining() < optionLen) {
                     throw new DeserializationException(
                             "Buffer underflow while reading DHCPv6 option");
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6ClientIdOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6ClientIdOption.java
index 0063bf6..5623e71 100644
--- a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6ClientIdOption.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6ClientIdOption.java
@@ -17,6 +17,7 @@
 
 package org.onlab.packet.dhcp;
 
+import com.google.common.base.MoreObjects;
 import org.onlab.packet.DHCP6;
 import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
@@ -87,4 +88,13 @@
         bb.put(payload.serialize());
         return bb.array();
     }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("code", getCode())
+                .add("length", getLength())
+                .add("duid", getDuid().toString())
+                .toString();
+    }
 }
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Duid.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Duid.java
index e8926ce..df5e4d4 100644
--- a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Duid.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Duid.java
@@ -17,11 +17,14 @@
 
 package org.onlab.packet.dhcp;
 
+import com.google.common.base.MoreObjects;
 import org.onlab.packet.BasePacket;
+import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
 import org.onlab.packet.IPacket;
 
 import java.nio.ByteBuffer;
+import java.util.Arrays;
 
 public class Dhcp6Duid extends BasePacket {
     private static final int DEFAULT_LLT_LEN = 8;
@@ -145,7 +148,11 @@
 
     @Override
     public IPacket deserialize(byte[] data, int offset, int length) {
-        return null;
+        try {
+            return deserializer().deserialize(data, offset, length);
+        } catch (DeserializationException e) {
+            throw new RuntimeException("Can't deserialize duid due to {}", e);
+        }
     }
 
     public static Deserializer<Dhcp6Duid> deserializer() {
@@ -178,4 +185,31 @@
             return duid;
         };
     }
+
+    @Override
+    public String toString() {
+        MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(getClass());
+
+        switch (duidType) {
+            case DUID_LLT:
+                helper.add("type", "DUID_LLT");
+                helper.add("hardwareType", hardwareType);
+                helper.add("duidTime", duidTime);
+                helper.add("linkLayerAddress", Arrays.toString(linkLayerAddress));
+                break;
+            case DUID_EN:
+                helper.add("type", "DUID_EN");
+                helper.add("enterpriseNumber", enterpriseNumber);
+                helper.add("id", Arrays.toString(identifier));
+                break;
+            case DUID_LL:
+                helper.add("type", "DUID_LL");
+                helper.add("hardwareType", hardwareType);
+                helper.add("linkLayerAddress", Arrays.toString(linkLayerAddress));
+                break;
+            default:
+                helper.add("type", "Unknown");
+        }
+        return helper.toString();
+    }
 }
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6IaNaOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6IaNaOption.java
index 578a2f9..f71de3a 100644
--- a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6IaNaOption.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6IaNaOption.java
@@ -174,7 +174,8 @@
                                                            optionData.length - bb.position());
                 short code = optByteBuffer.getShort();
                 short len = optByteBuffer.getShort();
-                byte[] subOptData = new byte[Dhcp6Option.DEFAULT_LEN + len];
+                int optLen = UNSIGNED_SHORT_MASK & len;
+                byte[] subOptData = new byte[Dhcp6Option.DEFAULT_LEN + optLen];
                 bb.get(subOptData);
 
                 // TODO: put more sub-options?
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6IaTaOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6IaTaOption.java
index e5eb211..e8fdba6 100644
--- a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6IaTaOption.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6IaTaOption.java
@@ -119,7 +119,8 @@
                                                            optionData.length - bb.position());
                 short code = optByteBuffer.getShort();
                 short len = optByteBuffer.getShort();
-                byte[] subOptData = new byte[Dhcp6Option.DEFAULT_LEN + len];
+                int optLen = UNSIGNED_SHORT_MASK & len;
+                byte[] subOptData = new byte[Dhcp6Option.DEFAULT_LEN + optLen];
                 bb.get(subOptData);
 
                 // TODO: put more sub-options?
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Option.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Option.java
index aaf3f66..597732d 100644
--- a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Option.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Option.java
@@ -34,6 +34,7 @@
  */
 public class Dhcp6Option extends BasePacket {
     public static final int DEFAULT_LEN = 4;
+    protected static final int UNSIGNED_SHORT_MASK = 0xffff;
     private short code;
     private short length;
     // XXX: use "payload" from BasePacket for option data.
@@ -50,8 +51,8 @@
      * @param dhcp6Option other DHCPv6 option
      */
     public Dhcp6Option(Dhcp6Option dhcp6Option) {
-        this.code = (short) (0xffff & dhcp6Option.code);
-        this.length = (short) (0xffff & dhcp6Option.length);
+        this.code = dhcp6Option.code;
+        this.length = dhcp6Option.length;
         this.payload = dhcp6Option.payload;
         this.payload.setParent(this);
     }
@@ -127,9 +128,10 @@
                                                            "should be at least 4 bytes");
             }
             ByteBuffer bb = ByteBuffer.wrap(data, offset, len);
-            dhcp6Option.code = (short) (0xff & bb.getShort());
-            dhcp6Option.length = (short) (0xff & bb.getShort());
-            byte[] optData = new byte[dhcp6Option.length];
+            dhcp6Option.code = bb.getShort();
+            dhcp6Option.length = bb.getShort();
+            int optionLen = UNSIGNED_SHORT_MASK & dhcp6Option.length;
+            byte[] optData = new byte[optionLen];
             bb.get(optData);
             dhcp6Option.setData(optData);
             return dhcp6Option;
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6RelayOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6RelayOption.java
index 9707f98..4133049 100644
--- a/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6RelayOption.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6RelayOption.java
@@ -17,6 +17,7 @@
 
 package org.onlab.packet.dhcp;
 
+import com.google.common.base.MoreObjects;
 import org.onlab.packet.DHCP6;
 import org.onlab.packet.Deserializer;
 import org.onlab.packet.IPacket;
@@ -36,6 +37,11 @@
         return (short) payload.serialize().length;
     }
 
+    @Override
+    public byte[] getData() {
+        return this.payload.serialize();
+    }
+
     /**
      * Default constructor.
      */
@@ -67,4 +73,13 @@
             return relayOption;
         };
     }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("code", getCode())
+                .add("length", getLength())
+                .add("data", payload.toString())
+                .toString();
+    }
 }
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpOption.java
index e54d6b1..76f768f 100644
--- a/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpOption.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpOption.java
@@ -34,6 +34,7 @@
 public class DhcpOption extends BasePacket {
     public static final int OPT_CODE_LEN = 1;
     public static final int DEFAULT_LEN = 2;
+    protected static final int UNSIGNED_BYTE_MASK = 0xff;
     private final Logger log = getLogger(getClass());
     protected byte code;
     protected byte length;
@@ -76,7 +77,8 @@
             dhcpOption.code = byteBuffer.get();
             if (byteBuffer.hasRemaining()) {
                 dhcpOption.length = byteBuffer.get();
-                dhcpOption.data = new byte[dhcpOption.length];
+                int optionLen = UNSIGNED_BYTE_MASK & dhcpOption.length;
+                dhcpOption.data = new byte[optionLen];
                 byteBuffer.get(dhcpOption.data);
             } else {
                 dhcpOption.length = 0;
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpRelayAgentOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpRelayAgentOption.java
index e60df53..adda088 100644
--- a/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpRelayAgentOption.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpRelayAgentOption.java
@@ -102,7 +102,8 @@
             while (byteBuffer.remaining() >= DEFAULT_LEN) {
                 byte subOptCode = byteBuffer.get();
                 byte subOptLen = byteBuffer.get();
-                byte[] subOptData = new byte[subOptLen];
+                int subOptLenInt = UNSIGNED_BYTE_MASK & subOptLen;
+                byte[] subOptData = new byte[subOptLenInt];
                 byteBuffer.get(subOptData);
 
                 DhcpOption subOption = new DhcpOption();