Fixing ONOS-4875

Change-Id: I2b4fec44f623cc6df90c45c1cabc8c40601bf4b6
(cherry picked from commit 1a5491ecaf6e648a547ea1265796835f7a24d300)
diff --git a/core/api/src/main/java/org/onosproject/net/host/InterfaceIpAddress.java b/core/api/src/main/java/org/onosproject/net/host/InterfaceIpAddress.java
index 1ceb784..4bf196d 100644
--- a/core/api/src/main/java/org/onosproject/net/host/InterfaceIpAddress.java
+++ b/core/api/src/main/java/org/onosproject/net/host/InterfaceIpAddress.java
@@ -60,11 +60,11 @@
      * @param subnetAddress the IP subnet address
      */
     public InterfaceIpAddress(IpAddress ipAddress, IpPrefix subnetAddress) {
-        this.ipAddress = checkNotNull(ipAddress);
-        this.subnetAddress = checkNotNull(subnetAddress);
-        // TODO: Recompute the default broadcast address from the subnet
-        // address
-        this.broadcastAddress = null;
+        checkArgument(checkNotNull(ipAddress).version() == checkNotNull(subnetAddress).version(),
+            "IP and subnet version mismatch");
+        this.ipAddress = ipAddress;
+        this.subnetAddress = subnetAddress;
+        this.broadcastAddress = computeBroadcastAddress(ipAddress, subnetAddress);
         this.peerAddress = null;
     }
 
@@ -78,8 +78,10 @@
      */
     public InterfaceIpAddress(IpAddress ipAddress, IpPrefix subnetAddress,
                               IpAddress broadcastAddress) {
-        this.ipAddress = checkNotNull(ipAddress);
-        this.subnetAddress = checkNotNull(subnetAddress);
+        checkArgument(checkNotNull(ipAddress).version() == checkNotNull(subnetAddress).version(),
+            "IP and subnet version mismatch");
+        this.ipAddress = ipAddress;
+        this.subnetAddress = subnetAddress;
         this.broadcastAddress = broadcastAddress;
         this.peerAddress = null;
     }
@@ -97,8 +99,10 @@
     public InterfaceIpAddress(IpAddress ipAddress, IpPrefix subnetAddress,
                               IpAddress broadcastAddress,
                               IpAddress peerAddress) {
-        this.ipAddress = checkNotNull(ipAddress);
-        this.subnetAddress = checkNotNull(subnetAddress);
+        checkArgument(checkNotNull(ipAddress).version() == checkNotNull(subnetAddress).version(),
+            "IP and subnet version mismatch");
+        this.ipAddress = ipAddress;
+        this.subnetAddress = subnetAddress;
         this.broadcastAddress = broadcastAddress;
         this.peerAddress = peerAddress;
     }
@@ -157,6 +161,21 @@
         return new InterfaceIpAddress(addr, subnet);
     }
 
+    /**
+     * Compute the IP broadcast address.
+     *
+     * @return the IP broadcast address
+     */
+    public static IpAddress computeBroadcastAddress(IpAddress ipAddress, IpPrefix subnetAddress) {
+        if (ipAddress.isIp6()) {
+            return null;
+        } else {
+            IpAddress maskedIP = IpAddress.makeMaskedAddress(ipAddress, subnetAddress.prefixLength());
+            int ipB = maskedIP.getIp4Address().toInt() | ((1 << (32 - subnetAddress.prefixLength())) - 1);
+            return IpAddress.valueOf(ipB);
+        }
+    }
+
     @Override
     public boolean equals(Object other) {
         if (other == this) {
diff --git a/core/api/src/test/java/org/onosproject/net/host/InterfaceIpAddressTest.java b/core/api/src/test/java/org/onosproject/net/host/InterfaceIpAddressTest.java
index cf80982..2dce173 100644
--- a/core/api/src/test/java/org/onosproject/net/host/InterfaceIpAddressTest.java
+++ b/core/api/src/test/java/org/onosproject/net/host/InterfaceIpAddressTest.java
@@ -34,6 +34,10 @@
     private static final IpAddress BROADCAST_ADDRESS =
         IpAddress.valueOf("1.2.0.255");         // NOTE: non-default broadcast
     private static final IpAddress PEER_ADDRESS = IpAddress.valueOf("5.6.7.8");
+    private static final IpAddress DEF_BROADCAST_ADDRESS =
+        IpAddress.valueOf("1.2.255.255");         // NOTE: default broadcast
+    private static final IpPrefix V6_SUBNET_ADDRESS =
+        IpPrefix.valueOf("::/64");
 
     private static final IpAddress IP_ADDRESS2 = IpAddress.valueOf("10.2.3.4");
     private static final IpPrefix SUBNET_ADDRESS2 =
@@ -97,8 +101,16 @@
             new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS);
         assertThat(addr.ipAddress(), is(IP_ADDRESS));
         assertThat(addr.subnetAddress(), is(SUBNET_ADDRESS));
-        assertThat(addr.broadcastAddress(), nullValue());
+        assertThat(addr.broadcastAddress(), is(DEF_BROADCAST_ADDRESS));
         assertThat(addr.peerAddress(), nullValue());
+
+        IpPrefix  subnetAddr = IpPrefix.valueOf("10.2.3.0/24");
+        InterfaceIpAddress addr1 = new InterfaceIpAddress(IP_ADDRESS2, subnetAddr);
+        assertThat(addr1.broadcastAddress().toString(), is("10.2.3.255"));
+
+        IpAddress ipAddress = IpAddress.valueOf("2001::4");
+        InterfaceIpAddress addr2 = new InterfaceIpAddress(ipAddress, V6_SUBNET_ADDRESS);
+        assertThat(addr2.broadcastAddress(), is(nullValue()));
     }
 
     /**
@@ -144,7 +156,7 @@
         addr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS);
         assertThat(addr.ipAddress().toString(), is("1.2.3.4"));
         assertThat(addr.subnetAddress().toString(), is("1.2.0.0/16"));
-        assertThat(addr.broadcastAddress(), is(nullValue()));   // TODO: Fix
+        assertThat(addr.broadcastAddress(), is(DEF_BROADCAST_ADDRESS));
         assertThat(addr.peerAddress(), is(nullValue()));
 
         // Interface address with non-default broadcast address
@@ -243,4 +255,11 @@
         assertThat(addr3, is(not(addr4)));
     }
 
+    /**
+     * Tests invalid class copy constructor for a null object to copy from.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testIllegalConstructorArgument() {
+        InterfaceIpAddress toAddr = new InterfaceIpAddress(IP_ADDRESS, V6_SUBNET_ADDRESS);
+    }
 }