DAD NS should not contain SRC_LL_ADDR option

Change-Id: I2022786d7d0d6673220ca6118e9b9d42d6484c74
diff --git a/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborSolicitation.java b/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborSolicitation.java
index 0df878e..82071da 100644
--- a/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborSolicitation.java
+++ b/utils/misc/src/main/java/org/onlab/packet/ndp/NeighborSolicitation.java
@@ -230,36 +230,29 @@
             return null;
         }
 
-        /*
-         * Here we craft the Ethernet packet.
-         */
+        // Here we craft the Ethernet packet.
         Ethernet ethernet = new Ethernet();
         ethernet.setEtherType(Ethernet.TYPE_IPV6)
                 .setDestinationMACAddress(destinationMac)
                 .setSourceMACAddress(sourceMac);
         ethernet.setVlanID(vlan.id());
-        /*
-         * IPv6 packet is created.
-         */
+        // IPv6 packet is created.
         IPv6 ipv6 = new IPv6();
         ipv6.setSourceAddress(sourceIp);
         ipv6.setDestinationAddress(destinationIp);
         ipv6.setHopLimit((byte) 255);
-        /*
-         * Create the ICMPv6 packet.
-         */
+        // Create the ICMPv6 packet.
         ICMP6 icmp6 = new ICMP6();
         icmp6.setIcmpType(ICMP6.NEIGHBOR_SOLICITATION);
         icmp6.setIcmpCode((byte) 0);
-        /*
-         * Create the Neighbor Solicitation packet.
-         */
+        // Create the Neighbor Solicitation packet.
         NeighborSolicitation ns = new NeighborSolicitation();
         ns.setTargetAddress(targetIp);
-        ns.addOption(NeighborDiscoveryOptions.TYPE_SOURCE_LL_ADDRESS, sourceMac);
-        /*
-         * Set the payloads
-         */
+        // DAD packets should not contain SRC_LL_ADDR option
+        if (!Arrays.equals(sourceIp, Ip6Address.ZERO.toOctets())) {
+            ns.addOption(NeighborDiscoveryOptions.TYPE_SOURCE_LL_ADDRESS, sourceMac);
+        }
+        // Set the payloads
         icmp6.setPayload(ns);
         ipv6.setPayload(icmp6);
         ethernet.setPayload(ipv6);
diff --git a/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborSolicitationTest.java b/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborSolicitationTest.java
index cc514f9..e01db27 100644
--- a/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborSolicitationTest.java
+++ b/utils/misc/src/test/java/org/onlab/packet/ndp/NeighborSolicitationTest.java
@@ -19,18 +19,31 @@
 import org.junit.Test;
 import org.onlab.packet.DeserializationException;
 import org.onlab.packet.Deserializer;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.ICMP6;
+import org.onlab.packet.IPv6;
+import org.onlab.packet.Ip6Address;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.PacketTestUtils;
+import org.onlab.packet.VlanId;
 
 import java.nio.ByteBuffer;
 
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.*;
+import static org.onlab.packet.ndp.NeighborDiscoveryOptions.TYPE_SOURCE_LL_ADDRESS;
 
 /**
  * Tests for class {@link NeighborSolicitation}.
  */
 public class NeighborSolicitationTest {
+    private static final Ip6Address TARGET_IP = Ip6Address.valueOf("2000::1");
+    private static final Ip6Address SRC_IP = Ip6Address.valueOf("2000::f");
+    private static final Ip6Address DST_IP = Ip6Address.valueOf("2000::1");
+    private static final MacAddress SRC_MAC = MacAddress.valueOf("00:00:00:00:00:0f");
+    private static final MacAddress DST_MAC = MacAddress.valueOf("00:00:00:00:00:01");
+    private static final VlanId VLAN_ID = VlanId.NONE;
+
     private static final byte[] TARGET_ADDRESS = {
         (byte) 0x20, (byte) 0x01, (byte) 0x0f, (byte) 0x18,
         (byte) 0x01, (byte) 0x13, (byte) 0x02, (byte) 0x15,
@@ -139,4 +152,37 @@
 
         // TODO: need to handle TARGET_ADDRESS and Options
     }
+
+    /**
+     * Tests regular non-DAD neighbor solicitation.
+     */
+    @Test
+    public void testBuildNdpSolicit() throws Exception {
+        Ethernet ethPacket = NeighborSolicitation.buildNdpSolicit(TARGET_IP.toOctets(),
+                SRC_IP.toOctets(), DST_IP.toOctets(),
+                SRC_MAC.toBytes(), DST_MAC.toBytes(), VLAN_ID);
+        IPv6 ipPacket = (IPv6) ethPacket.getPayload();
+        ICMP6 icmp6Packet = (ICMP6) ipPacket.getPayload();
+        NeighborSolicitation nsPacket = (NeighborSolicitation) icmp6Packet.getPayload();
+
+        assertEquals("Non-DAD NS should have 1 option", 1, nsPacket.getOptions().size());
+        assertEquals("The option should be SRC_LL_ADDR type", TYPE_SOURCE_LL_ADDRESS,
+                nsPacket.getOptions().stream().findFirst().get().type());
+    }
+
+    /**
+     * Tests DAD neighbor solicitation.
+     * Source IP should be all-zero.
+     */
+    @Test
+    public void testBuildNdpSolicitDad() throws Exception {
+        Ethernet ethPacket = NeighborSolicitation.buildNdpSolicit(TARGET_IP.toOctets(),
+                Ip6Address.ZERO.toOctets(), DST_IP.toOctets(),
+                SRC_MAC.toBytes(), DST_MAC.toBytes(), VLAN_ID);
+        IPv6 ipPacket = (IPv6) ethPacket.getPayload();
+        ICMP6 icmp6Packet = (ICMP6) ipPacket.getPayload();
+        NeighborSolicitation nsPacket = (NeighborSolicitation) icmp6Packet.getPayload();
+
+        assertEquals("DAD NS should have no option", 0, nsPacket.getOptions().size());
+    }
 }