[ONOS-5427] Add LISP Info-Request and Info-Reply message type

Change-Id: Ia54919945609a57e45b34af3bbe7b04e4a7efbec
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfo.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfo.java
new file mode 100644
index 0000000..14cd884
--- /dev/null
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfo.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2016-present 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.onosproject.lisp.msg.protocols;
+
+import io.netty.buffer.ByteBuf;
+import org.onlab.util.ByteOperator;
+import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.lisp.msg.exceptions.LispParseError;
+import org.onosproject.lisp.msg.exceptions.LispReaderException;
+import org.onosproject.lisp.msg.exceptions.LispWriterException;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+import org.onosproject.lisp.msg.types.LispAfiAddress.AfiAddressWriter;
+
+import java.util.Arrays;
+
+/**
+ * A class that contains a set of helper methods for LISP info request and reply.
+ */
+public class DefaultLispInfo implements LispInfo {
+
+    protected final boolean infoReply;
+    protected final long nonce;
+    protected final short keyId;
+    protected final short authDataLength;
+    protected final byte[] authenticationData;
+    protected final int ttl;
+    protected final byte maskLength;
+    protected final LispAfiAddress eidPrefix;
+
+    private static final int INFO_REPLY_INDEX = 3;
+    private static final int RESERVED_SKIP_LENGTH_1 = 3;
+    private static final int RESERVED_SKIP_LENGTH_2 = 1;
+
+    private static final int INFO_REQUEST_SHIFT_BIT = 4;
+
+    private static final int ENABLE_BIT = 1;
+    private static final int DISABLE_BIT = 0;
+
+    private static final int UNUSED_ZERO = 0;
+
+    /**
+     * A private constructor that protects object instantiation from external.
+     *
+     * @param infoReply          info reply flag
+     * @param nonce              nonce
+     * @param keyId              key identifier
+     * @param authDataLength     authentication data length
+     * @param authenticationData authentication data
+     * @param ttl                Time-To-Live value
+     * @param maskLength         EID prefix mask length
+     * @param eidPrefix          EID prefix
+     */
+    protected DefaultLispInfo(boolean infoReply, long nonce, short keyId, short authDataLength,
+                              byte[] authenticationData, int ttl, byte maskLength,
+                              LispAfiAddress eidPrefix) {
+        this.infoReply = infoReply;
+        this.nonce = nonce;
+        this.keyId = keyId;
+        this.authDataLength = authDataLength;
+        this.authenticationData = authenticationData;
+        this.ttl = ttl;
+        this.maskLength = maskLength;
+        this.eidPrefix = eidPrefix;
+    }
+
+    @Override
+    public LispType getType() {
+        return LispType.LISP_INFO;
+    }
+
+    @Override
+    public void writeTo(ByteBuf byteBuf) {
+        // TODO: serialize LispMapRegister message
+    }
+
+    @Override
+    public Builder createBuilder() {
+        return new DefaultLispInfoRequest.DefaultInfoRequestBuilder();
+    }
+
+    @Override
+    public boolean hasInfoReply() {
+        return infoReply;
+    }
+
+    @Override
+    public long getNonce() {
+        return nonce;
+    }
+
+    @Override
+    public short getKeyId() {
+        return keyId;
+    }
+
+    @Override
+    public short getAuthDataLength() {
+        return authDataLength;
+    }
+
+    @Override
+    public byte[] getAuthenticationData() {
+        if (authenticationData != null && authenticationData.length != 0) {
+            return ImmutableByteSequence.copyFrom(authenticationData).asArray();
+        } else {
+            return new byte[0];
+        }
+    }
+
+    @Override
+    public int getTtl() {
+        return ttl;
+    }
+
+    @Override
+    public byte getMaskLength() {
+        return maskLength;
+    }
+
+    @Override
+    public LispAfiAddress getPrefix() {
+        return eidPrefix;
+    }
+
+    public static LispInfo deserialize(ByteBuf byteBuf) throws LispParseError, LispReaderException {
+
+        if (byteBuf.readerIndex() != 0) {
+            return null;
+        }
+
+        // infoReply -> 1 bit
+        boolean infoReplyFlag = ByteOperator.getBit(byteBuf.readByte(), INFO_REPLY_INDEX);
+
+        // let's skip the reserved field
+        byteBuf.skipBytes(RESERVED_SKIP_LENGTH_1);
+
+        // nonce -> 64 bits
+        long nonce = byteBuf.readLong();
+
+        // keyId -> 16 bits
+        short keyId = byteBuf.readShort();
+
+        // authenticationDataLength -> 16 bits
+        short authLength = byteBuf.readShort();
+
+        // authenticationData -> depends on the authenticationDataLength
+        byte[] authData = new byte[authLength];
+        byteBuf.readBytes(authData);
+
+        // ttl -> 32 bits
+        int ttl = byteBuf.readInt();
+
+        // let's skip the reserved field
+        byteBuf.skipBytes(RESERVED_SKIP_LENGTH_2);
+
+        // mask length -> 8 bits
+        short maskLength = byteBuf.readUnsignedByte();
+
+        LispAfiAddress prefix = new LispAfiAddress.AfiAddressReader().readFrom(byteBuf);
+
+        return new DefaultLispInfo(infoReplyFlag, nonce, keyId, authLength,
+                authData, ttl, (byte) maskLength, prefix);
+    }
+
+    public static void serialize(ByteBuf byteBuf, LispInfo message) throws LispWriterException {
+
+        // specify LISP message type
+        byte msgType = (byte) (LispType.LISP_INFO.getTypeCode() << INFO_REQUEST_SHIFT_BIT);
+
+        // info reply flag
+        byte infoReply = DISABLE_BIT;
+        if (message.hasInfoReply()) {
+            infoReply = (byte) (ENABLE_BIT << INFO_REPLY_INDEX);
+        }
+
+        byteBuf.writeByte(msgType + infoReply);
+
+        // fill zero into reserved filed
+        byteBuf.writeByte((short) UNUSED_ZERO);
+        byteBuf.writeByte((short) UNUSED_ZERO);
+        byteBuf.writeByte((short) UNUSED_ZERO);
+
+        // nonce
+        byteBuf.writeLong(message.getNonce());
+
+        // keyId
+        byteBuf.writeShort(message.getKeyId());
+
+        // authentication data length in octet
+        byteBuf.writeShort(message.getAuthDataLength());
+
+        // authentication data
+        byte[] data = message.getAuthenticationData();
+        byte[] clone;
+        if (data != null) {
+            clone = data.clone();
+            Arrays.fill(clone, (byte) UNUSED_ZERO);
+        }
+
+        byteBuf.writeBytes(data);
+
+        // TODO: need to implement MAC authentication mechanism
+
+        /// TTL
+        byteBuf.writeInt(message.getTtl());
+
+        // fill zero into reserved filed
+        byteBuf.writeByte((short) UNUSED_ZERO);
+
+        // mask length
+        byteBuf.writeByte(message.getMaskLength());
+
+        // EID prefix AFI with EID prefix
+        AfiAddressWriter afiAddressWriter = new AfiAddressWriter();
+        afiAddressWriter.writeTo(byteBuf, message.getPrefix());
+    }
+}