Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.net;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertFalse;
     21 import static org.junit.Assert.assertTrue;
     22 import static org.junit.Assert.fail;
     23 
     24 import android.net.IpPrefix;
     25 import android.net.LinkAddress;
     26 import android.net.LinkProperties;
     27 import android.net.LinkProperties.CompareResult;
     28 import android.net.LinkProperties.ProvisioningChange;
     29 import android.net.RouteInfo;
     30 import android.os.Parcel;
     31 import android.support.test.filters.SmallTest;
     32 import android.support.test.runner.AndroidJUnit4;
     33 import android.system.OsConstants;
     34 import android.util.ArraySet;
     35 
     36 import java.net.InetAddress;
     37 import java.util.ArrayList;
     38 import java.util.Arrays;
     39 import java.util.Collection;
     40 import java.util.Collections;
     41 import java.util.List;
     42 import java.util.Set;
     43 
     44 import org.junit.Test;
     45 import org.junit.runner.RunWith;
     46 
     47 @RunWith(AndroidJUnit4.class)
     48 @SmallTest
     49 public class LinkPropertiesTest {
     50     private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
     51     private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress(
     52             "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
     53     private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1");
     54     private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1");
     55     private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888");
     56     private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1");
     57     private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1");
     58     private static InetAddress GATEWAY61 = NetworkUtils.numericToInetAddress("fe80::6:0000:613");
     59     private static InetAddress GATEWAY62 = NetworkUtils.numericToInetAddress("fe80::6:2222");
     60     private static String NAME = "qmi0";
     61     private static int MTU = 1500;
     62 
     63     private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
     64     private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
     65     private static LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
     66 
     67     // TODO: replace all calls to NetworkUtils.numericToInetAddress with calls to this method.
     68     private InetAddress Address(String addrString) {
     69         return NetworkUtils.numericToInetAddress(addrString);
     70     }
     71 
     72     public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
     73         // Check implementation of equals(), element by element.
     74         assertTrue(source.isIdenticalInterfaceName(target));
     75         assertTrue(target.isIdenticalInterfaceName(source));
     76 
     77         assertTrue(source.isIdenticalAddresses(target));
     78         assertTrue(target.isIdenticalAddresses(source));
     79 
     80         assertTrue(source.isIdenticalDnses(target));
     81         assertTrue(target.isIdenticalDnses(source));
     82 
     83         assertTrue(source.isIdenticalPrivateDns(target));
     84         assertTrue(target.isIdenticalPrivateDns(source));
     85 
     86         assertTrue(source.isIdenticalValidatedPrivateDnses(target));
     87         assertTrue(target.isIdenticalValidatedPrivateDnses(source));
     88 
     89         assertTrue(source.isIdenticalRoutes(target));
     90         assertTrue(target.isIdenticalRoutes(source));
     91 
     92         assertTrue(source.isIdenticalHttpProxy(target));
     93         assertTrue(target.isIdenticalHttpProxy(source));
     94 
     95         assertTrue(source.isIdenticalStackedLinks(target));
     96         assertTrue(target.isIdenticalStackedLinks(source));
     97 
     98         assertTrue(source.isIdenticalMtu(target));
     99         assertTrue(target.isIdenticalMtu(source));
    100 
    101         assertTrue(source.isIdenticalTcpBufferSizes(target));
    102         assertTrue(target.isIdenticalTcpBufferSizes(source));
    103 
    104         // Check result of equals().
    105         assertTrue(source.equals(target));
    106         assertTrue(target.equals(source));
    107 
    108         // Check hashCode.
    109         assertEquals(source.hashCode(), target.hashCode());
    110     }
    111 
    112     @Test
    113     public void testEqualsNull() {
    114         LinkProperties source = new LinkProperties();
    115         LinkProperties target = new LinkProperties();
    116 
    117         assertFalse(source == target);
    118         assertLinkPropertiesEqual(source, target);
    119     }
    120 
    121     @Test
    122     public void testEqualsSameOrder() throws Exception {
    123         LinkProperties source = new LinkProperties();
    124         source.setInterfaceName(NAME);
    125         // set 2 link addresses
    126         source.addLinkAddress(LINKADDRV4);
    127         source.addLinkAddress(LINKADDRV6);
    128         // set 2 dnses
    129         source.addDnsServer(DNS1);
    130         source.addDnsServer(DNS2);
    131         // set 2 gateways
    132         source.addRoute(new RouteInfo(GATEWAY1));
    133         source.addRoute(new RouteInfo(GATEWAY2));
    134         source.setMtu(MTU);
    135 
    136         LinkProperties target = new LinkProperties();
    137 
    138         // All fields are same
    139         target.setInterfaceName(NAME);
    140         target.addLinkAddress(LINKADDRV4);
    141         target.addLinkAddress(LINKADDRV6);
    142         target.addDnsServer(DNS1);
    143         target.addDnsServer(DNS2);
    144         target.addRoute(new RouteInfo(GATEWAY1));
    145         target.addRoute(new RouteInfo(GATEWAY2));
    146         target.setMtu(MTU);
    147 
    148         assertLinkPropertiesEqual(source, target);
    149 
    150         target.clear();
    151         // change Interface Name
    152         target.setInterfaceName("qmi1");
    153         target.addLinkAddress(LINKADDRV4);
    154         target.addLinkAddress(LINKADDRV6);
    155         target.addDnsServer(DNS1);
    156         target.addDnsServer(DNS2);
    157         target.addRoute(new RouteInfo(GATEWAY1));
    158         target.addRoute(new RouteInfo(GATEWAY2));
    159         target.setMtu(MTU);
    160         assertFalse(source.equals(target));
    161 
    162         target.clear();
    163         target.setInterfaceName(NAME);
    164         // change link addresses
    165         target.addLinkAddress(new LinkAddress(
    166                 NetworkUtils.numericToInetAddress("75.208.6.2"), 32));
    167         target.addLinkAddress(LINKADDRV6);
    168         target.addDnsServer(DNS1);
    169         target.addDnsServer(DNS2);
    170         target.addRoute(new RouteInfo(GATEWAY1));
    171         target.addRoute(new RouteInfo(GATEWAY2));
    172         target.setMtu(MTU);
    173         assertFalse(source.equals(target));
    174 
    175         target.clear();
    176         target.setInterfaceName(NAME);
    177         target.addLinkAddress(LINKADDRV4);
    178         target.addLinkAddress(LINKADDRV6);
    179         // change dnses
    180         target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
    181         target.addDnsServer(DNS2);
    182         target.addRoute(new RouteInfo(GATEWAY1));
    183         target.addRoute(new RouteInfo(GATEWAY2));
    184         target.setMtu(MTU);
    185         assertFalse(source.equals(target));
    186 
    187         target.clear();
    188         target.setInterfaceName(NAME);
    189         target.addLinkAddress(LINKADDRV4);
    190         target.addLinkAddress(LINKADDRV6);
    191         target.addDnsServer(DNS1);
    192         target.addDnsServer(DNS2);
    193         // change gateway
    194         target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
    195         target.addRoute(new RouteInfo(GATEWAY2));
    196         target.setMtu(MTU);
    197         assertFalse(source.equals(target));
    198 
    199         target.clear();
    200         target.setInterfaceName(NAME);
    201         target.addLinkAddress(LINKADDRV4);
    202         target.addLinkAddress(LINKADDRV6);
    203         target.addDnsServer(DNS1);
    204         target.addDnsServer(DNS2);
    205         target.addRoute(new RouteInfo(GATEWAY1));
    206         target.addRoute(new RouteInfo(GATEWAY2));
    207         // change mtu
    208         target.setMtu(1440);
    209         assertFalse(source.equals(target));
    210     }
    211 
    212     @Test
    213     public void testEqualsDifferentOrder() throws Exception {
    214         LinkProperties source = new LinkProperties();
    215         source.setInterfaceName(NAME);
    216         // set 2 link addresses
    217         source.addLinkAddress(LINKADDRV4);
    218         source.addLinkAddress(LINKADDRV6);
    219         // set 2 dnses
    220         source.addDnsServer(DNS1);
    221         source.addDnsServer(DNS2);
    222         // set 2 gateways
    223         source.addRoute(new RouteInfo(GATEWAY1));
    224         source.addRoute(new RouteInfo(GATEWAY2));
    225         source.setMtu(MTU);
    226 
    227         LinkProperties target = new LinkProperties();
    228         // Exchange order
    229         target.setInterfaceName(NAME);
    230         target.addLinkAddress(LINKADDRV6);
    231         target.addLinkAddress(LINKADDRV4);
    232         target.addDnsServer(DNS2);
    233         target.addDnsServer(DNS1);
    234         target.addRoute(new RouteInfo(GATEWAY2));
    235         target.addRoute(new RouteInfo(GATEWAY1));
    236         target.setMtu(MTU);
    237 
    238         assertLinkPropertiesEqual(source, target);
    239     }
    240 
    241     @Test
    242     public void testEqualsDuplicated() throws Exception {
    243         LinkProperties source = new LinkProperties();
    244         // set 3 link addresses, eg, [A, A, B]
    245         source.addLinkAddress(LINKADDRV4);
    246         source.addLinkAddress(LINKADDRV4);
    247         source.addLinkAddress(LINKADDRV6);
    248 
    249         LinkProperties target = new LinkProperties();
    250         // set 3 link addresses, eg, [A, B, B]
    251         target.addLinkAddress(LINKADDRV4);
    252         target.addLinkAddress(LINKADDRV6);
    253         target.addLinkAddress(LINKADDRV6);
    254 
    255         assertLinkPropertiesEqual(source, target);
    256     }
    257 
    258     private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) {
    259         for (RouteInfo r : lp.getRoutes()) {
    260             assertEquals(iface, r.getInterface());
    261         }
    262     }
    263 
    264     @Test
    265     public void testRouteInterfaces() {
    266         LinkAddress prefix = new LinkAddress(
    267             NetworkUtils.numericToInetAddress("2001:db8::"), 32);
    268         InetAddress address = ADDRV6;
    269 
    270         // Add a route with no interface to a LinkProperties with no interface. No errors.
    271         LinkProperties lp = new LinkProperties();
    272         RouteInfo r = new RouteInfo(prefix, address, null);
    273         assertTrue(lp.addRoute(r));
    274         assertEquals(1, lp.getRoutes().size());
    275         assertAllRoutesHaveInterface(null, lp);
    276 
    277         // Adding the same route twice has no effect.
    278         assertFalse(lp.addRoute(r));
    279         assertEquals(1, lp.getRoutes().size());
    280 
    281         // Add a route with an interface. Expect an exception.
    282         r = new RouteInfo(prefix, address, "wlan0");
    283         try {
    284           lp.addRoute(r);
    285           fail("Adding wlan0 route to LP with no interface, expect exception");
    286         } catch (IllegalArgumentException expected) {}
    287 
    288         // Change the interface name. All the routes should change their interface name too.
    289         lp.setInterfaceName("rmnet0");
    290         assertAllRoutesHaveInterface("rmnet0", lp);
    291 
    292         // Now add a route with the wrong interface. This causes an exception too.
    293         try {
    294           lp.addRoute(r);
    295           fail("Adding wlan0 route to rmnet0 LP, expect exception");
    296         } catch (IllegalArgumentException expected) {}
    297 
    298         // If the interface name matches, the route is added.
    299         r = new RouteInfo(prefix, null, "wlan0");
    300         lp.setInterfaceName("wlan0");
    301         lp.addRoute(r);
    302         assertEquals(2, lp.getRoutes().size());
    303         assertAllRoutesHaveInterface("wlan0", lp);
    304 
    305         // Routes with null interfaces are converted to wlan0.
    306         r = RouteInfo.makeHostRoute(ADDRV6, null);
    307         lp.addRoute(r);
    308         assertEquals(3, lp.getRoutes().size());
    309         assertAllRoutesHaveInterface("wlan0", lp);
    310 
    311         // Check comparisons work.
    312         LinkProperties lp2 = new LinkProperties(lp);
    313         assertAllRoutesHaveInterface("wlan0", lp);
    314         assertEquals(0, lp.compareAllRoutes(lp2).added.size());
    315         assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
    316 
    317         lp2.setInterfaceName("p2p0");
    318         assertAllRoutesHaveInterface("p2p0", lp2);
    319         assertEquals(3, lp.compareAllRoutes(lp2).added.size());
    320         assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
    321     }
    322 
    323     @Test
    324     public void testStackedInterfaces() {
    325         LinkProperties rmnet0 = new LinkProperties();
    326         rmnet0.setInterfaceName("rmnet0");
    327         rmnet0.addLinkAddress(LINKADDRV6);
    328 
    329         LinkProperties clat4 = new LinkProperties();
    330         clat4.setInterfaceName("clat4");
    331         clat4.addLinkAddress(LINKADDRV4);
    332 
    333         assertEquals(0, rmnet0.getStackedLinks().size());
    334         assertEquals(1, rmnet0.getAddresses().size());
    335         assertEquals(1, rmnet0.getLinkAddresses().size());
    336         assertEquals(1, rmnet0.getAllAddresses().size());
    337         assertEquals(1, rmnet0.getAllLinkAddresses().size());
    338 
    339         rmnet0.addStackedLink(clat4);
    340         assertEquals(1, rmnet0.getStackedLinks().size());
    341         assertEquals(1, rmnet0.getAddresses().size());
    342         assertEquals(1, rmnet0.getLinkAddresses().size());
    343         assertEquals(2, rmnet0.getAllAddresses().size());
    344         assertEquals(2, rmnet0.getAllLinkAddresses().size());
    345 
    346         rmnet0.addStackedLink(clat4);
    347         assertEquals(1, rmnet0.getStackedLinks().size());
    348         assertEquals(1, rmnet0.getAddresses().size());
    349         assertEquals(1, rmnet0.getLinkAddresses().size());
    350         assertEquals(2, rmnet0.getAllAddresses().size());
    351         assertEquals(2, rmnet0.getAllLinkAddresses().size());
    352 
    353         assertEquals(0, clat4.getStackedLinks().size());
    354 
    355         // Modify an item in the returned collection to see what happens.
    356         for (LinkProperties link : rmnet0.getStackedLinks()) {
    357             if (link.getInterfaceName().equals("clat4")) {
    358                link.setInterfaceName("newname");
    359             }
    360         }
    361         for (LinkProperties link : rmnet0.getStackedLinks()) {
    362             assertFalse("newname".equals(link.getInterfaceName()));
    363         }
    364 
    365         assertTrue(rmnet0.removeStackedLink("clat4"));
    366         assertEquals(0, rmnet0.getStackedLinks().size());
    367         assertEquals(1, rmnet0.getAddresses().size());
    368         assertEquals(1, rmnet0.getLinkAddresses().size());
    369         assertEquals(1, rmnet0.getAllAddresses().size());
    370         assertEquals(1, rmnet0.getAllLinkAddresses().size());
    371 
    372         assertFalse(rmnet0.removeStackedLink("clat4"));
    373     }
    374 
    375     private LinkAddress getFirstLinkAddress(LinkProperties lp) {
    376         return lp.getLinkAddresses().iterator().next();
    377     }
    378 
    379     @Test
    380     public void testAddressMethods() {
    381         LinkProperties lp = new LinkProperties();
    382 
    383         // No addresses.
    384         assertFalse(lp.hasIPv4Address());
    385         assertFalse(lp.hasGlobalIPv6Address());
    386 
    387         // Addresses on stacked links don't count.
    388         LinkProperties stacked = new LinkProperties();
    389         stacked.setInterfaceName("stacked");
    390         lp.addStackedLink(stacked);
    391         stacked.addLinkAddress(LINKADDRV4);
    392         stacked.addLinkAddress(LINKADDRV6);
    393         assertTrue(stacked.hasIPv4Address());
    394         assertTrue(stacked.hasGlobalIPv6Address());
    395         assertFalse(lp.hasIPv4Address());
    396         assertFalse(lp.hasGlobalIPv6Address());
    397         lp.removeStackedLink("stacked");
    398         assertFalse(lp.hasIPv4Address());
    399         assertFalse(lp.hasGlobalIPv6Address());
    400 
    401         // Addresses on the base link.
    402         // Check the return values of hasIPvXAddress and ensure the add/remove methods return true
    403         // iff something changes.
    404         assertEquals(0, lp.getLinkAddresses().size());
    405         assertTrue(lp.addLinkAddress(LINKADDRV6));
    406         assertEquals(1, lp.getLinkAddresses().size());
    407         assertFalse(lp.hasIPv4Address());
    408         assertTrue(lp.hasGlobalIPv6Address());
    409 
    410         assertTrue(lp.removeLinkAddress(LINKADDRV6));
    411         assertEquals(0, lp.getLinkAddresses().size());
    412 
    413         assertTrue(lp.addLinkAddress(LINKADDRV6LINKLOCAL));
    414         assertEquals(1, lp.getLinkAddresses().size());
    415         assertFalse(lp.hasGlobalIPv6Address());
    416 
    417         assertTrue(lp.addLinkAddress(LINKADDRV4));
    418         assertEquals(2, lp.getLinkAddresses().size());
    419         assertTrue(lp.hasIPv4Address());
    420         assertFalse(lp.hasGlobalIPv6Address());
    421 
    422         assertTrue(lp.addLinkAddress(LINKADDRV6));
    423         assertEquals(3, lp.getLinkAddresses().size());
    424         assertTrue(lp.hasIPv4Address());
    425         assertTrue(lp.hasGlobalIPv6Address());
    426 
    427         assertTrue(lp.removeLinkAddress(LINKADDRV6LINKLOCAL));
    428         assertEquals(2, lp.getLinkAddresses().size());
    429         assertTrue(lp.hasIPv4Address());
    430         assertTrue(lp.hasGlobalIPv6Address());
    431 
    432         // Adding an address twice has no effect.
    433         // Removing an address that's not present has no effect.
    434         assertFalse(lp.addLinkAddress(LINKADDRV4));
    435         assertEquals(2, lp.getLinkAddresses().size());
    436         assertTrue(lp.hasIPv4Address());
    437         assertTrue(lp.removeLinkAddress(LINKADDRV4));
    438         assertEquals(1, lp.getLinkAddresses().size());
    439         assertFalse(lp.hasIPv4Address());
    440         assertFalse(lp.removeLinkAddress(LINKADDRV4));
    441         assertEquals(1, lp.getLinkAddresses().size());
    442 
    443         // Adding an address that's already present but with different properties causes the
    444         // existing address to be updated and returns true.
    445         // Start with only LINKADDRV6.
    446         assertEquals(1, lp.getLinkAddresses().size());
    447         assertEquals(LINKADDRV6, getFirstLinkAddress(lp));
    448 
    449         // Create a LinkAddress object for the same address, but with different flags.
    450         LinkAddress deprecated = new LinkAddress(ADDRV6, 128,
    451                 OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE);
    452         assertTrue(deprecated.isSameAddressAs(LINKADDRV6));
    453         assertFalse(deprecated.equals(LINKADDRV6));
    454 
    455         // Check that adding it updates the existing address instead of adding a new one.
    456         assertTrue(lp.addLinkAddress(deprecated));
    457         assertEquals(1, lp.getLinkAddresses().size());
    458         assertEquals(deprecated, getFirstLinkAddress(lp));
    459         assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp)));
    460 
    461         // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties.
    462         assertTrue(lp.removeLinkAddress(LINKADDRV6));
    463         assertEquals(0, lp.getLinkAddresses().size());
    464     }
    465 
    466     @Test
    467     public void testSetLinkAddresses() {
    468         LinkProperties lp = new LinkProperties();
    469         lp.addLinkAddress(LINKADDRV4);
    470         lp.addLinkAddress(LINKADDRV6);
    471 
    472         LinkProperties lp2 = new LinkProperties();
    473         lp2.addLinkAddress(LINKADDRV6);
    474 
    475         assertFalse(lp.equals(lp2));
    476 
    477         lp2.setLinkAddresses(lp.getLinkAddresses());
    478         assertTrue(lp.equals(lp));
    479     }
    480 
    481     @Test
    482     public void testIsProvisioned() {
    483         LinkProperties lp4 = new LinkProperties();
    484         assertFalse("v4only:empty", lp4.isProvisioned());
    485         lp4.addLinkAddress(LINKADDRV4);
    486         assertFalse("v4only:addr-only", lp4.isProvisioned());
    487         lp4.addDnsServer(DNS1);
    488         assertFalse("v4only:addr+dns", lp4.isProvisioned());
    489         lp4.addRoute(new RouteInfo(GATEWAY1));
    490         assertTrue("v4only:addr+dns+route", lp4.isProvisioned());
    491         assertTrue("v4only:addr+dns+route", lp4.isIPv4Provisioned());
    492         assertFalse("v4only:addr+dns+route", lp4.isIPv6Provisioned());
    493 
    494         LinkProperties lp6 = new LinkProperties();
    495         assertFalse("v6only:empty", lp6.isProvisioned());
    496         lp6.addLinkAddress(LINKADDRV6LINKLOCAL);
    497         assertFalse("v6only:fe80-only", lp6.isProvisioned());
    498         lp6.addDnsServer(DNS6);
    499         assertFalse("v6only:fe80+dns", lp6.isProvisioned());
    500         lp6.addRoute(new RouteInfo(GATEWAY61));
    501         assertFalse("v6only:fe80+dns+route", lp6.isProvisioned());
    502         lp6.addLinkAddress(LINKADDRV6);
    503         assertTrue("v6only:fe80+global+dns+route", lp6.isIPv6Provisioned());
    504         assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned());
    505         lp6.removeLinkAddress(LINKADDRV6LINKLOCAL);
    506         assertFalse("v6only:global+dns+route", lp6.isIPv4Provisioned());
    507         assertTrue("v6only:global+dns+route", lp6.isIPv6Provisioned());
    508         assertTrue("v6only:global+dns+route", lp6.isProvisioned());
    509 
    510         LinkProperties lp46 = new LinkProperties();
    511         lp46.addLinkAddress(LINKADDRV4);
    512         lp46.addLinkAddress(LINKADDRV6);
    513         lp46.addDnsServer(DNS1);
    514         lp46.addDnsServer(DNS6);
    515         assertFalse("dualstack:missing-routes", lp46.isProvisioned());
    516         lp46.addRoute(new RouteInfo(GATEWAY1));
    517         assertTrue("dualstack:v4-provisioned", lp46.isIPv4Provisioned());
    518         assertFalse("dualstack:v4-provisioned", lp46.isIPv6Provisioned());
    519         assertTrue("dualstack:v4-provisioned", lp46.isProvisioned());
    520         lp46.addRoute(new RouteInfo(GATEWAY61));
    521         assertTrue("dualstack:both-provisioned", lp46.isIPv4Provisioned());
    522         assertTrue("dualstack:both-provisioned", lp46.isIPv6Provisioned());
    523         assertTrue("dualstack:both-provisioned", lp46.isProvisioned());
    524 
    525         // A link with an IPv6 address and default route, but IPv4 DNS server.
    526         LinkProperties mixed = new LinkProperties();
    527         mixed.addLinkAddress(LINKADDRV6);
    528         mixed.addDnsServer(DNS1);
    529         mixed.addRoute(new RouteInfo(GATEWAY61));
    530         assertFalse("mixed:addr6+route6+dns4", mixed.isIPv4Provisioned());
    531         assertFalse("mixed:addr6+route6+dns4", mixed.isIPv6Provisioned());
    532         assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned());
    533     }
    534 
    535     @Test
    536     public void testCompareProvisioning() {
    537         LinkProperties v4lp = new LinkProperties();
    538         v4lp.addLinkAddress(LINKADDRV4);
    539         v4lp.addRoute(new RouteInfo(GATEWAY1));
    540         v4lp.addDnsServer(DNS1);
    541         assertTrue(v4lp.isProvisioned());
    542 
    543         LinkProperties v4r = new LinkProperties(v4lp);
    544         v4r.removeDnsServer(DNS1);
    545         assertFalse(v4r.isProvisioned());
    546 
    547         assertEquals(ProvisioningChange.STILL_NOT_PROVISIONED,
    548                 LinkProperties.compareProvisioning(v4r, v4r));
    549         assertEquals(ProvisioningChange.LOST_PROVISIONING,
    550                 LinkProperties.compareProvisioning(v4lp, v4r));
    551         assertEquals(ProvisioningChange.GAINED_PROVISIONING,
    552                 LinkProperties.compareProvisioning(v4r, v4lp));
    553         assertEquals(ProvisioningChange.STILL_PROVISIONED,
    554                 LinkProperties.compareProvisioning(v4lp, v4lp));
    555 
    556         // Check that losing IPv4 provisioning on a dualstack network is
    557         // seen as a total loss of provisioning.
    558         LinkProperties v6lp = new LinkProperties();
    559         v6lp.addLinkAddress(LINKADDRV6);
    560         v6lp.addRoute(new RouteInfo(GATEWAY61));
    561         v6lp.addDnsServer(DNS6);
    562         assertFalse(v6lp.isIPv4Provisioned());
    563         assertTrue(v6lp.isIPv6Provisioned());
    564         assertTrue(v6lp.isProvisioned());
    565 
    566         LinkProperties v46lp = new LinkProperties(v6lp);
    567         v46lp.addLinkAddress(LINKADDRV4);
    568         v46lp.addRoute(new RouteInfo(GATEWAY1));
    569         v46lp.addDnsServer(DNS1);
    570         assertTrue(v46lp.isIPv4Provisioned());
    571         assertTrue(v46lp.isIPv6Provisioned());
    572         assertTrue(v46lp.isProvisioned());
    573 
    574         assertEquals(ProvisioningChange.STILL_PROVISIONED,
    575                 LinkProperties.compareProvisioning(v4lp, v46lp));
    576         assertEquals(ProvisioningChange.STILL_PROVISIONED,
    577                 LinkProperties.compareProvisioning(v6lp, v46lp));
    578         assertEquals(ProvisioningChange.LOST_PROVISIONING,
    579                 LinkProperties.compareProvisioning(v46lp, v6lp));
    580         assertEquals(ProvisioningChange.LOST_PROVISIONING,
    581                 LinkProperties.compareProvisioning(v46lp, v4lp));
    582 
    583         // Check that losing and gaining a secondary router does not change
    584         // the provisioning status.
    585         LinkProperties v6lp2 = new LinkProperties(v6lp);
    586         v6lp2.addRoute(new RouteInfo(GATEWAY62));
    587         assertTrue(v6lp2.isProvisioned());
    588 
    589         assertEquals(ProvisioningChange.STILL_PROVISIONED,
    590                 LinkProperties.compareProvisioning(v6lp2, v6lp));
    591         assertEquals(ProvisioningChange.STILL_PROVISIONED,
    592                 LinkProperties.compareProvisioning(v6lp, v6lp2));
    593     }
    594 
    595     @Test
    596     public void testIsReachable() {
    597         final LinkProperties v4lp = new LinkProperties();
    598         assertFalse(v4lp.isReachable(DNS1));
    599         assertFalse(v4lp.isReachable(DNS2));
    600 
    601         // Add an on-link route, making the on-link DNS server reachable,
    602         // but there is still no IPv4 address.
    603         assertTrue(v4lp.addRoute(new RouteInfo(
    604                 new IpPrefix(NetworkUtils.numericToInetAddress("75.208.0.0"), 16))));
    605         assertFalse(v4lp.isReachable(DNS1));
    606         assertFalse(v4lp.isReachable(DNS2));
    607 
    608         // Adding an IPv4 address (right now, any IPv4 address) means we use
    609         // the routes to compute likely reachability.
    610         assertTrue(v4lp.addLinkAddress(new LinkAddress(ADDRV4, 16)));
    611         assertTrue(v4lp.isReachable(DNS1));
    612         assertFalse(v4lp.isReachable(DNS2));
    613 
    614         // Adding a default route makes the off-link DNS server reachable.
    615         assertTrue(v4lp.addRoute(new RouteInfo(GATEWAY1)));
    616         assertTrue(v4lp.isReachable(DNS1));
    617         assertTrue(v4lp.isReachable(DNS2));
    618 
    619         final LinkProperties v6lp = new LinkProperties();
    620         final InetAddress kLinkLocalDns = NetworkUtils.numericToInetAddress("fe80::6:1");
    621         final InetAddress kLinkLocalDnsWithScope = NetworkUtils.numericToInetAddress("fe80::6:2%43");
    622         final InetAddress kOnLinkDns = NetworkUtils.numericToInetAddress("2001:db8:85a3::53");
    623         assertFalse(v6lp.isReachable(kLinkLocalDns));
    624         assertFalse(v6lp.isReachable(kLinkLocalDnsWithScope));
    625         assertFalse(v6lp.isReachable(kOnLinkDns));
    626         assertFalse(v6lp.isReachable(DNS6));
    627 
    628         // Add a link-local route, making the link-local DNS servers reachable. Because
    629         // we assume the presence of an IPv6 link-local address, link-local DNS servers
    630         // are considered reachable, but only those with a non-zero scope identifier.
    631         assertTrue(v6lp.addRoute(new RouteInfo(
    632                 new IpPrefix(NetworkUtils.numericToInetAddress("fe80::"), 64))));
    633         assertFalse(v6lp.isReachable(kLinkLocalDns));
    634         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
    635         assertFalse(v6lp.isReachable(kOnLinkDns));
    636         assertFalse(v6lp.isReachable(DNS6));
    637 
    638         // Add a link-local address--nothing changes.
    639         assertTrue(v6lp.addLinkAddress(LINKADDRV6LINKLOCAL));
    640         assertFalse(v6lp.isReachable(kLinkLocalDns));
    641         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
    642         assertFalse(v6lp.isReachable(kOnLinkDns));
    643         assertFalse(v6lp.isReachable(DNS6));
    644 
    645         // Add a global route on link, but no global address yet. DNS servers reachable
    646         // via a route that doesn't require a gateway: give them the benefit of the
    647         // doubt and hope the link-local source address suffices for communication.
    648         assertTrue(v6lp.addRoute(new RouteInfo(
    649                 new IpPrefix(NetworkUtils.numericToInetAddress("2001:db8:85a3::"), 64))));
    650         assertFalse(v6lp.isReachable(kLinkLocalDns));
    651         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
    652         assertTrue(v6lp.isReachable(kOnLinkDns));
    653         assertFalse(v6lp.isReachable(DNS6));
    654 
    655         // Add a global address; the on-link global address DNS server is (still)
    656         // presumed reachable.
    657         assertTrue(v6lp.addLinkAddress(new LinkAddress(ADDRV6, 64)));
    658         assertFalse(v6lp.isReachable(kLinkLocalDns));
    659         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
    660         assertTrue(v6lp.isReachable(kOnLinkDns));
    661         assertFalse(v6lp.isReachable(DNS6));
    662 
    663         // Adding a default route makes the off-link DNS server reachable.
    664         assertTrue(v6lp.addRoute(new RouteInfo(GATEWAY62)));
    665         assertFalse(v6lp.isReachable(kLinkLocalDns));
    666         assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
    667         assertTrue(v6lp.isReachable(kOnLinkDns));
    668         assertTrue(v6lp.isReachable(DNS6));
    669 
    670         // Check isReachable on stacked links. This requires that the source IP address be assigned
    671         // on the interface returned by the route lookup.
    672         LinkProperties stacked = new LinkProperties();
    673 
    674         // Can't add a stacked link without an interface name.
    675         stacked.setInterfaceName("v4-test0");
    676         v6lp.addStackedLink(stacked);
    677 
    678         InetAddress stackedAddress = Address("192.0.0.4");
    679         LinkAddress stackedLinkAddress = new LinkAddress(stackedAddress, 32);
    680         assertFalse(v6lp.isReachable(stackedAddress));
    681         stacked.addLinkAddress(stackedLinkAddress);
    682         assertFalse(v6lp.isReachable(stackedAddress));
    683         stacked.addRoute(new RouteInfo(stackedLinkAddress));
    684         assertTrue(stacked.isReachable(stackedAddress));
    685         assertTrue(v6lp.isReachable(stackedAddress));
    686 
    687         assertFalse(v6lp.isReachable(DNS1));
    688         stacked.addRoute(new RouteInfo((IpPrefix) null, stackedAddress));
    689         assertTrue(v6lp.isReachable(DNS1));
    690     }
    691 
    692     @Test
    693     public void testLinkPropertiesEnsureDirectlyConnectedRoutes() {
    694         // IPv4 case: no route added initially
    695         LinkProperties rmnet0 = new LinkProperties();
    696         rmnet0.setInterfaceName("rmnet0");
    697         rmnet0.addLinkAddress(new LinkAddress("10.0.0.2/8"));
    698         RouteInfo directRoute0 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
    699                 rmnet0.getInterfaceName());
    700 
    701         // Since no routes is added explicitly, getAllRoutes() should return empty.
    702         assertTrue(rmnet0.getAllRoutes().isEmpty());
    703         rmnet0.ensureDirectlyConnectedRoutes();
    704         // ensureDirectlyConnectedRoutes() should have added the missing local route.
    705         assertEqualRoutes(Collections.singletonList(directRoute0), rmnet0.getAllRoutes());
    706 
    707         // IPv4 case: both direct and default routes added initially
    708         LinkProperties rmnet1 = new LinkProperties();
    709         rmnet1.setInterfaceName("rmnet1");
    710         rmnet1.addLinkAddress(new LinkAddress("10.0.0.3/8"));
    711         RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null,
    712                 NetworkUtils.numericToInetAddress("10.0.0.1"), rmnet1.getInterfaceName());
    713         RouteInfo directRoute1 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
    714                 rmnet1.getInterfaceName());
    715         rmnet1.addRoute(defaultRoute1);
    716         rmnet1.addRoute(directRoute1);
    717 
    718         // Check added routes
    719         assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
    720         // ensureDirectlyConnectedRoutes() shouldn't change the routes since direct connected
    721         // route is already part of the configuration.
    722         rmnet1.ensureDirectlyConnectedRoutes();
    723         assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
    724 
    725         // IPv6 case: only default routes added initially
    726         LinkProperties rmnet2 = new LinkProperties();
    727         rmnet2.setInterfaceName("rmnet2");
    728         rmnet2.addLinkAddress(new LinkAddress("fe80::cafe/64"));
    729         rmnet2.addLinkAddress(new LinkAddress("2001:db8::2/64"));
    730         RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null,
    731                 NetworkUtils.numericToInetAddress("2001:db8::1"), rmnet2.getInterfaceName());
    732         RouteInfo directRoute2 = new RouteInfo(new IpPrefix("2001:db8::/64"), null,
    733                 rmnet2.getInterfaceName());
    734         RouteInfo linkLocalRoute2 = new RouteInfo(new IpPrefix("fe80::/64"), null,
    735                 rmnet2.getInterfaceName());
    736         rmnet2.addRoute(defaultRoute2);
    737 
    738         assertEqualRoutes(Arrays.asList(defaultRoute2), rmnet2.getAllRoutes());
    739         rmnet2.ensureDirectlyConnectedRoutes();
    740         assertEqualRoutes(Arrays.asList(defaultRoute2, directRoute2, linkLocalRoute2),
    741                 rmnet2.getAllRoutes());
    742 
    743         // Corner case: no interface name
    744         LinkProperties rmnet3 = new LinkProperties();
    745         rmnet3.addLinkAddress(new LinkAddress("192.168.0.2/24"));
    746         RouteInfo directRoute3 = new RouteInfo(new IpPrefix("192.168.0.0/24"), null,
    747                 rmnet3.getInterfaceName());
    748 
    749         assertTrue(rmnet3.getAllRoutes().isEmpty());
    750         rmnet3.ensureDirectlyConnectedRoutes();
    751         assertEqualRoutes(Collections.singletonList(directRoute3), rmnet3.getAllRoutes());
    752 
    753     }
    754 
    755     @Test
    756     public void testCompareResult() {
    757         // Either adding or removing items
    758         compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(1),
    759                 Arrays.asList(2, 3, 4), new ArrayList<>());
    760         compareResult(Arrays.asList(1, 2), Arrays.asList(3, 2, 1, 4),
    761                 new ArrayList<>(), Arrays.asList(3, 4));
    762 
    763 
    764         // adding and removing items at the same time
    765         compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(2, 3, 4, 5),
    766                 Arrays.asList(1), Arrays.asList(5));
    767         compareResult(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6),
    768                 Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));
    769 
    770         // null cases
    771         compareResult(Arrays.asList(1, 2, 3), null, Arrays.asList(1, 2, 3), new ArrayList<>());
    772         compareResult(null, Arrays.asList(3, 2, 1), new ArrayList<>(), Arrays.asList(1, 2, 3));
    773         compareResult(null, null, new ArrayList<>(), new ArrayList<>());
    774     }
    775 
    776     private void assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual) {
    777         Set<RouteInfo> expectedSet = new ArraySet<>(expected);
    778         Set<RouteInfo> actualSet = new ArraySet<>(actual);
    779         // Duplicated entries in actual routes are considered failures
    780         assertEquals(actual.size(), actualSet.size());
    781 
    782         assertEquals(expectedSet, actualSet);
    783     }
    784 
    785     private <T> void compareResult(List<T> oldItems, List<T> newItems, List<T> expectRemoved,
    786             List<T> expectAdded) {
    787         CompareResult<T> result = new CompareResult<>(oldItems, newItems);
    788         assertEquals(new ArraySet<>(expectAdded), new ArraySet<>(result.added));
    789         assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
    790     }
    791 
    792     @Test
    793     public void testLinkPropertiesParcelable() {
    794         LinkProperties source = new LinkProperties();
    795         source.setInterfaceName(NAME);
    796         // set 2 link addresses
    797         source.addLinkAddress(LINKADDRV4);
    798         source.addLinkAddress(LINKADDRV6);
    799         // set 2 dnses
    800         source.addDnsServer(DNS1);
    801         source.addDnsServer(DNS2);
    802         // set 2 gateways
    803         source.addRoute(new RouteInfo(GATEWAY1));
    804         source.addRoute(new RouteInfo(GATEWAY2));
    805         // set 2 validated private dnses
    806         source.addValidatedPrivateDnsServer(DNS6);
    807         source.addValidatedPrivateDnsServer(GATEWAY61);
    808 
    809         source.setMtu(MTU);
    810 
    811         Parcel p = Parcel.obtain();
    812         source.writeToParcel(p, /* flags */ 0);
    813         p.setDataPosition(0);
    814         final byte[] marshalled = p.marshall();
    815         p = Parcel.obtain();
    816         p.unmarshall(marshalled, 0, marshalled.length);
    817         p.setDataPosition(0);
    818         LinkProperties dest = LinkProperties.CREATOR.createFromParcel(p);
    819 
    820         assertEquals(source, dest);
    821     }
    822 }
    823