[ONOS-5623] Enhance map server to handle Info-Request control msg

Change-Id: If5f68041fbef786e912fc17e33a0e296df73cd3d
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/LispChannelHandler.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/LispChannelHandler.java
index 1b14a2f..1041370 100644
--- a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/LispChannelHandler.java
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/LispChannelHandler.java
@@ -21,6 +21,8 @@
 import io.netty.handler.timeout.IdleStateEvent;
 import io.netty.util.ReferenceCountUtil;
 import org.onosproject.lisp.msg.protocols.LispEncapsulatedControl;
+import org.onosproject.lisp.msg.protocols.LispInfoReply;
+import org.onosproject.lisp.msg.protocols.LispInfoRequest;
 import org.onosproject.lisp.msg.protocols.LispMapNotify;
 import org.onosproject.lisp.msg.protocols.LispMapRegister;
 import org.onosproject.lisp.msg.protocols.LispMapRequest;
@@ -64,6 +66,16 @@
         } finally {
             ReferenceCountUtil.release(msg);
         }
+
+        if (msg instanceof LispInfoRequest) {
+            LispMapServer mapServer = new LispMapServer();
+            LispInfoReply infoReply = mapServer.processInfoRequest((LispInfoRequest) msg);
+
+            // try to remove the received info-request message from buffer
+            ReferenceCountUtil.release(msg);
+
+            ctx.writeAndFlush(infoReply);
+        }
     }
 
     @Override
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/LispMapServer.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/LispMapServer.java
index bcc726a..4e555ee 100644
--- a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/LispMapServer.java
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/LispMapServer.java
@@ -15,21 +15,35 @@
  */
 package org.onosproject.lisp.ctl;
 
+import org.onlab.packet.IpAddress;
+import org.onosproject.lisp.msg.protocols.DefaultLispInfoReply;
 import org.onosproject.lisp.msg.protocols.DefaultLispMapNotify.DefaultNotifyBuilder;
 import org.onosproject.lisp.msg.protocols.DefaultLispMapRegister.DefaultRegisterBuilder;
 import org.onosproject.lisp.msg.protocols.LispEidRecord;
+import org.onosproject.lisp.msg.protocols.LispInfoReply;
+import org.onosproject.lisp.msg.protocols.LispInfoReply.InfoReplyBuilder;
+import org.onosproject.lisp.msg.protocols.LispInfoRequest;
+import org.onosproject.lisp.msg.protocols.LispInfoRequest.InfoRequestBuilder;
 import org.onosproject.lisp.msg.protocols.LispMapNotify;
 import org.onosproject.lisp.msg.protocols.LispMapNotify.NotifyBuilder;
 import org.onosproject.lisp.msg.protocols.LispMapRegister;
 import org.onosproject.lisp.msg.protocols.LispMapRegister.RegisterBuilder;
 import org.onosproject.lisp.msg.protocols.LispMessage;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+import org.onosproject.lisp.msg.types.LispIpv4Address;
+import org.onosproject.lisp.msg.types.LispIpv6Address;
+import org.onosproject.lisp.msg.types.LispNoAddress;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
 import java.util.Arrays;
 
 import static org.onosproject.lisp.msg.authentication.LispAuthenticationKeyEnum.valueOf;
+import static org.onosproject.lisp.msg.protocols.DefaultLispInfoRequest.DefaultInfoRequestBuilder;
+import static org.onosproject.lisp.msg.types.LispNatLcafAddress.NatAddressBuilder;
 
 /**
  * LISP map server class.
@@ -38,6 +52,7 @@
 public class LispMapServer {
 
     private static final int MAP_NOTIFY_PORT = 4342;
+    private static final int INFO_REPLY_PORT = 4342;
 
     // TODO: need to be configurable
     private static final String AUTH_KEY = "onos";
@@ -91,6 +106,62 @@
     }
 
     /**
+     * Handles info-request message and replies with info-reply message.
+     *
+     * @param message info-request message
+     * @return info-reply message
+     */
+    public LispInfoReply processInfoRequest(LispMessage message) {
+        LispInfoRequest request = (LispInfoRequest) message;
+
+        if (!checkInfoRequestAuthData(request)) {
+            log.warn("Unmatched authentication data of Info-Request");
+            return null;
+        }
+
+        NatAddressBuilder natBuilder = new NatAddressBuilder();
+        try {
+            LispAfiAddress msAddress =
+                    new LispIpv4Address(IpAddress.valueOf(InetAddress.getLocalHost()));
+            natBuilder.withMsRlocAddress(msAddress);
+            natBuilder.withMsUdpPortNumber((short) INFO_REPLY_PORT);
+
+            // try to extract global ETR RLOC address from info-request
+            IpAddress globalRlocIp = IpAddress.valueOf(request.getSender().getAddress());
+            LispAfiAddress globalRlocAddress;
+            if (globalRlocIp.isIp4()) {
+                globalRlocAddress = new LispIpv4Address(globalRlocIp);
+            } else {
+                globalRlocAddress = new LispIpv6Address(globalRlocIp);
+            }
+            natBuilder.withGlobalEtrRlocAddress(globalRlocAddress);
+            natBuilder.withEtrUdpPortNumber((short) request.getSender().getPort());
+            natBuilder.withPrivateEtrRlocAddress(new LispNoAddress());
+
+            // TODO: need to specify RTR addresses
+
+        } catch (UnknownHostException e) {
+            log.warn("Fails during formulate NAT address", e);
+        }
+
+        InfoReplyBuilder replyBuilder = new DefaultLispInfoReply.DefaultInfoReplyBuilder();
+        replyBuilder.withKeyId(request.getKeyId());
+        replyBuilder.withAuthDataLength(valueOf(AUTH_METHOD).getHashLength());
+        replyBuilder.withAuthKey(AUTH_KEY);
+        replyBuilder.withNonce(request.getNonce());
+        replyBuilder.withEidPrefix(request.getPrefix());
+        replyBuilder.withMaskLength(request.getMaskLength());
+        replyBuilder.withTtl(request.getTtl());
+        replyBuilder.withNatLcafAddress(natBuilder.build());
+        replyBuilder.withIsInfoReply(true);
+
+        LispInfoReply reply = replyBuilder.build();
+        reply.configSender(request.getSender());
+
+        return reply;
+    }
+
+    /**
      * Checks the integrity of the received map-register message by calculating
      * authentication data from received map-register message.
      *
@@ -105,8 +176,31 @@
         registerBuilder.withIsProxyMapReply(register.isProxyMapReply());
         registerBuilder.withIsWantMapNotify(register.isWantMapNotify());
         registerBuilder.withMapRecords(register.getMapRecords());
+
         LispMapRegister authRegister = registerBuilder.build();
 
         return Arrays.equals(authRegister.getAuthData(), register.getAuthData());
     }
+
+    /**
+     * Checks the integrity of the received info-request message by calculating
+     * authentication data from received info-request message.
+     *
+     * @param request info-request message
+     * @return evaluation result
+     */
+    private boolean checkInfoRequestAuthData(LispInfoRequest request) {
+        InfoRequestBuilder requestBuilder = new DefaultInfoRequestBuilder();
+        requestBuilder.withKeyId(request.getKeyId());
+        requestBuilder.withAuthKey(AUTH_KEY);
+        requestBuilder.withNonce(request.getNonce());
+        requestBuilder.withTtl(request.getTtl());
+        requestBuilder.withEidPrefix(request.getPrefix());
+        requestBuilder.withIsInfoReply(request.isInfoReply());
+        requestBuilder.withMaskLength(request.getMaskLength());
+
+        LispInfoRequest authRequest =  requestBuilder.build();
+
+        return Arrays.equals(authRequest.getAuthData(), request.getAuthData());
+    }
 }
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoReply.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoReply.java
index 29cd39e..5ab4f96 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoReply.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoReply.java
@@ -128,7 +128,7 @@
 
 
         @Override
-        public InfoReplyBuilder withInfoReply(boolean infoReply) {
+        public InfoReplyBuilder withIsInfoReply(boolean infoReply) {
             this.infoReply = infoReply;
             return this;
         }
@@ -236,7 +236,7 @@
             LispNatLcafAddress natLcafAddress = new LispNatLcafAddress.NatLcafAddressReader().readFrom(byteBuf);
 
             return new DefaultInfoReplyBuilder()
-                    .withInfoReply(lispInfo.isInfoReply())
+                    .withIsInfoReply(lispInfo.isInfoReply())
                     .withNonce(lispInfo.getNonce())
                     .withKeyId(lispInfo.getKeyId())
                     .withAuthDataLength(lispInfo.getAuthDataLength())
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoRequest.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoRequest.java
index a24fd1a..18a055f 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoRequest.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoRequest.java
@@ -114,7 +114,7 @@
 
 
         @Override
-        public InfoRequestBuilder withInfoReply(boolean infoReply) {
+        public InfoRequestBuilder withIsInfoReply(boolean infoReply) {
             this.infoReply = infoReply;
             return this;
         }
@@ -215,7 +215,7 @@
             LispInfo lispInfo = DefaultLispInfo.deserialize(byteBuf);
 
             return new DefaultInfoRequestBuilder()
-                    .withInfoReply(lispInfo.isInfoReply())
+                    .withIsInfoReply(lispInfo.isInfoReply())
                     .withNonce(lispInfo.getNonce())
                     .withKeyId(lispInfo.getKeyId())
                     .withAuthDataLength(lispInfo.getAuthDataLength())
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/InfoBuilder.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/InfoBuilder.java
index 655eb49..159bbd7 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/InfoBuilder.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/InfoBuilder.java
@@ -29,7 +29,7 @@
      * @param infoReply info reply
      * @return T object
      */
-    T withInfoReply(boolean infoReply);
+    T withIsInfoReply(boolean infoReply);
 
     /**
      * Sets nonce value.
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispInfoReply.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispInfoReply.java
index 05c642c..4e8af92 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispInfoReply.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispInfoReply.java
@@ -20,8 +20,8 @@
 /**
  * LISP info reply message interface.
  * <p>
- * LISP info reply message format is defined in draft-ermagan-lisp-nat-traversal-01.
- * https://tools.ietf.org/html/draft-ermagan-lisp-nat-traversal-01#page-8
+ * LISP info reply message format is defined in draft-ermagan-lisp-nat-traversal-11.
+ * https://tools.ietf.org/html/draft-ermagan-lisp-nat-traversal-11#page-9
  *
  * <pre>
  * {@literal
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispInfoRequest.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispInfoRequest.java
index 81a9dcf..40fb1f8 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispInfoRequest.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/protocols/LispInfoRequest.java
@@ -18,8 +18,8 @@
 /**
  * LISP info request message interface.
  * <p>
- * LISP info request message format is defined in draft-ermagan-lisp-nat-traversal-01.
- * https://tools.ietf.org/html/draft-ermagan-lisp-nat-traversal-01#page-7
+ * LISP info request message format is defined in draft-ermagan-lisp-nat-traversal-11.
+ * https://tools.ietf.org/html/draft-ermagan-lisp-nat-traversal-11#page-7
  *
  * <pre>
  * {@literal
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAfiAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAfiAddress.java
index 7f67277..0942431 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAfiAddress.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispAfiAddress.java
@@ -92,6 +92,7 @@
             // handle no address
             if (afiCode == NO_ADDRESS.getIanaCode()) {
                 byteBuf.readUnsignedShort();
+                return new LispNoAddress.NoAddressReader().readFrom(byteBuf);
             }
 
             // handle IPv4 and IPv6 address
@@ -136,6 +137,9 @@
             byteBuf.writeShort(address.getAfi().getIanaCode());
 
             switch (address.getAfi()) {
+                case NO_ADDRESS:
+                    new LispNoAddress.NoAddressWriter().writeTo(byteBuf, (LispNoAddress) address);
+                    break;
                 case IP4:
                     new LispIpAddress.IpAddressWriter().writeTo(byteBuf, (LispIpv4Address) address);
                     break;
diff --git a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispNoAddress.java b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispNoAddress.java
index a8894eb..a36c386 100644
--- a/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispNoAddress.java
+++ b/protocols/lisp/msg/src/main/java/org/onosproject/lisp/msg/types/LispNoAddress.java
@@ -49,7 +49,7 @@
 
         @Override
         public void writeTo(ByteBuf byteBuf, LispNoAddress address) throws LispWriterException {
-
+            // since there is nothing to write to channel, we just leave it empty
         }
     }
 }
diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoReplyTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoReplyTest.java
index 7e3849a..6b68d54 100644
--- a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoReplyTest.java
+++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoReplyTest.java
@@ -72,7 +72,7 @@
                     .withNonce(1L)
                     .withKeyId((short) 1)
                     .withAuthKey(AUTH_KEY)
-                    .withInfoReply(false)
+                    .withIsInfoReply(false)
                     .withMaskLength((byte) 1)
                     .withEidPrefix(address1)
                     .withNatLcafAddress(natLcafAddress1).build();
@@ -83,7 +83,7 @@
                             .withNonce(1L)
                             .withKeyId((short) 1)
                             .withAuthKey(AUTH_KEY)
-                            .withInfoReply(false)
+                            .withIsInfoReply(false)
                             .withMaskLength((byte) 1)
                             .withEidPrefix(address1)
                             .withNatLcafAddress(natLcafAddress1).build();
@@ -111,7 +111,7 @@
                         .withNonce(2L)
                         .withKeyId((short) 2)
                         .withAuthKey(AUTH_KEY)
-                        .withInfoReply(true)
+                        .withIsInfoReply(true)
                         .withMaskLength((byte) 1)
                         .withEidPrefix(address2)
                         .withNatLcafAddress(natLcafAddress2).build();
diff --git a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoRequestTest.java b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoRequestTest.java
index 83b6f89..fe433b0 100644
--- a/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoRequestTest.java
+++ b/protocols/lisp/msg/src/test/java/org/onosproject/lisp/msg/protocols/DefaultLispInfoRequestTest.java
@@ -55,7 +55,7 @@
                         .withNonce(1L)
                         .withKeyId((short) 1)
                         .withAuthKey(AUTH_KEY)
-                        .withInfoReply(false)
+                        .withIsInfoReply(false)
                         .withMaskLength((byte) 1)
                         .withEidPrefix(address1).build();
 
@@ -65,7 +65,7 @@
                             .withNonce(1L)
                             .withKeyId((short) 1)
                             .withAuthKey(AUTH_KEY)
-                            .withInfoReply(false)
+                            .withIsInfoReply(false)
                             .withMaskLength((byte) 1)
                             .withEidPrefix(address1).build();
 
@@ -77,7 +77,7 @@
                         .withNonce(2L)
                         .withKeyId((short) 2)
                         .withAuthKey(AUTH_KEY)
-                        .withInfoReply(true)
+                        .withIsInfoReply(true)
                         .withMaskLength((byte) 1)
                         .withEidPrefix(address2).build();
     }