Added packet handling functions for PIM, Specifically
PIM Hello and PIM Join/Prune messages along with
respective PIM encoded address types

Change-Id: Iaef2e3581e27fa910ad355043bcb3e175238706a
diff --git a/utils/misc/src/main/java/org/onlab/packet/pim/PIMHello.java b/utils/misc/src/main/java/org/onlab/packet/pim/PIMHello.java
new file mode 100644
index 0000000..d454f1a
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/pim/PIMHello.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onlab.packet.pim;
+
+import org.onlab.packet.BasePacket;
+import org.onlab.packet.Deserializer;
+import org.onlab.packet.IPacket;
+import org.onlab.packet.IpAddress;
+
+import java.nio.ByteBuffer;
+import java.util.Random;
+
+import static org.onlab.packet.PacketUtils.checkInput;
+
+public class PIMHello extends BasePacket {
+
+    private IpAddress nbrIpAddress;
+
+    private int holdtime = 105;
+    private int genid = 0;
+    private int priority = 1;
+    private boolean priorityPresent = false;
+
+    public static final int MINIMUM_OPTION_LEN_BYTES = 4;
+
+    /**
+     * PIM Option types.
+     */
+    public enum Option {
+        HOLDTIME  (1, 2),
+        PRUNEDELAY(2, 4),
+        PRIORITY  (19, 4),
+        GENID     (20, 4),
+        ADDRLIST  (24, 0);
+
+        private final int optType;
+        private final int optLen;
+
+        Option(int ot, int ol) {
+            this.optType = ot;
+            this.optLen = ol;
+        }
+
+        public int optType() {
+            return this.optType;
+        }
+
+        public int optLen() {
+            return this.optLen;
+        }
+    }
+
+    /**
+     * Add the holdtime to the packet.
+     *
+     * @param holdtime the holdtime in seconds
+     */
+    public void addHoldtime(int holdtime) {
+        this.holdtime = holdtime;
+    }
+
+    /**
+     * Add the hello priority.
+     *
+     * @param priority default is 1, the higher the better
+     */
+    public void addPriority(int priority) {
+        this.priority = priority;
+        this.priorityPresent = true;
+    }
+
+    /**
+     * Add a Gen ID.
+     *
+     * @param genid a random generated number, changes only after reset.
+     */
+    public void addGenId(int genid) {
+        if (genid == 0) {
+            this.addGenId();
+        } else {
+            this.genid = genid;
+        }
+    }
+
+    /**
+     * Add the genid.  Let this function figure out the number.
+     */
+    public void addGenId() {
+        Random rand = new Random();
+        this.genid = rand.nextInt();
+    }
+
+    /**
+     * Sets all payloads parent packet if applicable, then serializes this
+     * packet and all payloads.
+     *
+     * @return a byte[] containing this packet and payloads
+     */
+    @Override
+    public byte[] serialize() {
+
+        // TODO: Figure out a better way to calculate buffer size
+        int size = Option.PRIORITY.optLen() + 4 +
+                Option.GENID.optLen() + 4 +
+                Option.HOLDTIME.optLen() + 4;
+
+        byte[] data = new byte[size];      // Come up with something better
+        ByteBuffer bb = ByteBuffer.wrap(data);
+
+        // Add the priority
+        bb.putShort((short) Option.PRIORITY.optType);
+        bb.putShort((short) Option.PRIORITY.optLen);
+        bb.putInt(this.priority);
+
+        // Add the genid
+        bb.putShort((short) Option.GENID.optType);
+        bb.putShort((short) Option.GENID.optLen);
+        bb.putInt(this.genid);
+
+        // Add the holdtime
+        bb.putShort((short) Option.HOLDTIME.optType);
+        bb.putShort((short) Option.HOLDTIME.optLen);
+        bb.putShort((short) this.holdtime);
+        return data;
+    }
+
+    /**
+     * XXX: This is deprecated, DO NOT USE, use the deserializer() function instead.
+     */
+    // @Override
+    public IPacket deserialize(final byte[] data, final int offset,
+                               final int length) {
+        //
+        return null;
+    }
+
+    /**
+     * Deserialize this hello message.
+     *
+     * @return a deserialized hello message.
+     */
+    public static Deserializer<PIMHello> deserializer() {
+        return (data, offset, length) -> {
+            checkInput(data, offset, length, MINIMUM_OPTION_LEN_BYTES);
+            final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
+
+            PIMHello hello = new PIMHello();
+            while (bb.hasRemaining()) {
+                int optType = bb.getShort();
+                int optLen  = bb.getShort();
+
+                // Check that we have enough buffer for the next option.
+                checkInput(data, bb.position(), bb.limit() - bb.position(), optLen);
+                if (optType == Option.GENID.optType) {
+                    hello.addGenId(bb.getInt());
+                } else if (optType == Option.PRIORITY.optType) {
+                    hello.addPriority(bb.getInt());
+                } else if (optType == Option.HOLDTIME.optType) {
+                    hello.addHoldtime((int) bb.getShort());
+                }
+            }
+
+            return hello;
+        };
+    }
+}