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
17package android.net;
18
19import android.net.LinkProperties;
20import android.net.RouteInfo;
21import android.system.OsConstants;
22import android.test.suitebuilder.annotation.SmallTest;
23import junit.framework.TestCase;
24
25import java.net.InetAddress;
26import java.util.ArrayList;
27
28public class LinkPropertiesTest extends TestCase {
29    private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
30    private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress(
31            "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
32    private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1");
33    private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1");
34    private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888");
35    private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1");
36    private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1");
37    private static InetAddress GATEWAY6 = NetworkUtils.numericToInetAddress("fe80::6:0000:613");
38    private static String NAME = "qmi0";
39    private static int MTU = 1500;
40
41    private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
42    private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
43    private static LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
44
45    public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
46        // Check implementation of equals(), element by element.
47        assertTrue(source.isIdenticalInterfaceName(target));
48        assertTrue(target.isIdenticalInterfaceName(source));
49
50        assertTrue(source.isIdenticalAddresses(target));
51        assertTrue(target.isIdenticalAddresses(source));
52
53        assertTrue(source.isIdenticalDnses(target));
54        assertTrue(target.isIdenticalDnses(source));
55
56        assertTrue(source.isIdenticalRoutes(target));
57        assertTrue(target.isIdenticalRoutes(source));
58
59        assertTrue(source.isIdenticalHttpProxy(target));
60        assertTrue(target.isIdenticalHttpProxy(source));
61
62        assertTrue(source.isIdenticalStackedLinks(target));
63        assertTrue(target.isIdenticalStackedLinks(source));
64
65        assertTrue(source.isIdenticalMtu(target));
66        assertTrue(target.isIdenticalMtu(source));
67
68        // Check result of equals().
69        assertTrue(source.equals(target));
70        assertTrue(target.equals(source));
71
72        // Check hashCode.
73        assertEquals(source.hashCode(), target.hashCode());
74    }
75
76    @SmallTest
77    public void testEqualsNull() {
78        LinkProperties source = new LinkProperties();
79        LinkProperties target = new LinkProperties();
80
81        assertFalse(source == target);
82        assertLinkPropertiesEqual(source, target);
83    }
84
85    @SmallTest
86    public void testEqualsSameOrder() {
87        try {
88            LinkProperties source = new LinkProperties();
89            source.setInterfaceName(NAME);
90            // set 2 link addresses
91            source.addLinkAddress(LINKADDRV4);
92            source.addLinkAddress(LINKADDRV6);
93            // set 2 dnses
94            source.addDnsServer(DNS1);
95            source.addDnsServer(DNS2);
96            // set 2 gateways
97            source.addRoute(new RouteInfo(GATEWAY1));
98            source.addRoute(new RouteInfo(GATEWAY2));
99            source.setMtu(MTU);
100
101            LinkProperties target = new LinkProperties();
102
103            // All fields are same
104            target.setInterfaceName(NAME);
105            target.addLinkAddress(LINKADDRV4);
106            target.addLinkAddress(LINKADDRV6);
107            target.addDnsServer(DNS1);
108            target.addDnsServer(DNS2);
109            target.addRoute(new RouteInfo(GATEWAY1));
110            target.addRoute(new RouteInfo(GATEWAY2));
111            target.setMtu(MTU);
112
113            assertLinkPropertiesEqual(source, target);
114
115            target.clear();
116            // change Interface Name
117            target.setInterfaceName("qmi1");
118            target.addLinkAddress(LINKADDRV4);
119            target.addLinkAddress(LINKADDRV6);
120            target.addDnsServer(DNS1);
121            target.addDnsServer(DNS2);
122            target.addRoute(new RouteInfo(GATEWAY1));
123            target.addRoute(new RouteInfo(GATEWAY2));
124            target.setMtu(MTU);
125            assertFalse(source.equals(target));
126
127            target.clear();
128            target.setInterfaceName(NAME);
129            // change link addresses
130            target.addLinkAddress(new LinkAddress(
131                    NetworkUtils.numericToInetAddress("75.208.6.2"), 32));
132            target.addLinkAddress(LINKADDRV6);
133            target.addDnsServer(DNS1);
134            target.addDnsServer(DNS2);
135            target.addRoute(new RouteInfo(GATEWAY1));
136            target.addRoute(new RouteInfo(GATEWAY2));
137            target.setMtu(MTU);
138            assertFalse(source.equals(target));
139
140            target.clear();
141            target.setInterfaceName(NAME);
142            target.addLinkAddress(LINKADDRV4);
143            target.addLinkAddress(LINKADDRV6);
144            // change dnses
145            target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
146            target.addDnsServer(DNS2);
147            target.addRoute(new RouteInfo(GATEWAY1));
148            target.addRoute(new RouteInfo(GATEWAY2));
149            target.setMtu(MTU);
150            assertFalse(source.equals(target));
151
152            target.clear();
153            target.setInterfaceName(NAME);
154            target.addLinkAddress(LINKADDRV4);
155            target.addLinkAddress(LINKADDRV6);
156            target.addDnsServer(DNS1);
157            target.addDnsServer(DNS2);
158            // change gateway
159            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
160            target.addRoute(new RouteInfo(GATEWAY2));
161            target.setMtu(MTU);
162            assertFalse(source.equals(target));
163
164            target.clear();
165            target.setInterfaceName(NAME);
166            target.addLinkAddress(LINKADDRV4);
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            // change mtu
173            target.setMtu(1440);
174            assertFalse(source.equals(target));
175
176        } catch (Exception e) {
177            throw new RuntimeException(e.toString());
178            //fail();
179        }
180    }
181
182    @SmallTest
183    public void testEqualsDifferentOrder() {
184        try {
185            LinkProperties source = new LinkProperties();
186            source.setInterfaceName(NAME);
187            // set 2 link addresses
188            source.addLinkAddress(LINKADDRV4);
189            source.addLinkAddress(LINKADDRV6);
190            // set 2 dnses
191            source.addDnsServer(DNS1);
192            source.addDnsServer(DNS2);
193            // set 2 gateways
194            source.addRoute(new RouteInfo(GATEWAY1));
195            source.addRoute(new RouteInfo(GATEWAY2));
196            source.setMtu(MTU);
197
198            LinkProperties target = new LinkProperties();
199            // Exchange order
200            target.setInterfaceName(NAME);
201            target.addLinkAddress(LINKADDRV6);
202            target.addLinkAddress(LINKADDRV4);
203            target.addDnsServer(DNS2);
204            target.addDnsServer(DNS1);
205            target.addRoute(new RouteInfo(GATEWAY2));
206            target.addRoute(new RouteInfo(GATEWAY1));
207            target.setMtu(MTU);
208
209            assertLinkPropertiesEqual(source, target);
210        } catch (Exception e) {
211            fail();
212        }
213    }
214
215    @SmallTest
216    public void testEqualsDuplicated() {
217        try {
218            LinkProperties source = new LinkProperties();
219            // set 3 link addresses, eg, [A, A, B]
220            source.addLinkAddress(LINKADDRV4);
221            source.addLinkAddress(LINKADDRV4);
222            source.addLinkAddress(LINKADDRV6);
223
224            LinkProperties target = new LinkProperties();
225            // set 3 link addresses, eg, [A, B, B]
226            target.addLinkAddress(LINKADDRV4);
227            target.addLinkAddress(LINKADDRV6);
228            target.addLinkAddress(LINKADDRV6);
229
230            assertLinkPropertiesEqual(source, target);
231        } catch (Exception e) {
232            fail();
233        }
234    }
235
236    private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) {
237        for (RouteInfo r : lp.getRoutes()) {
238            assertEquals(iface, r.getInterface());
239        }
240    }
241
242    @SmallTest
243    public void testRouteInterfaces() {
244        LinkAddress prefix = new LinkAddress(
245            NetworkUtils.numericToInetAddress("2001:db8::"), 32);
246        InetAddress address = ADDRV6;
247
248        // Add a route with no interface to a LinkProperties with no interface. No errors.
249        LinkProperties lp = new LinkProperties();
250        RouteInfo r = new RouteInfo(prefix, address, null);
251        assertTrue(lp.addRoute(r));
252        assertEquals(1, lp.getRoutes().size());
253        assertAllRoutesHaveInterface(null, lp);
254
255        // Adding the same route twice has no effect.
256        assertFalse(lp.addRoute(r));
257        assertEquals(1, lp.getRoutes().size());
258
259        // Add a route with an interface. Expect an exception.
260        r = new RouteInfo(prefix, address, "wlan0");
261        try {
262          lp.addRoute(r);
263          fail("Adding wlan0 route to LP with no interface, expect exception");
264        } catch (IllegalArgumentException expected) {}
265
266        // Change the interface name. All the routes should change their interface name too.
267        lp.setInterfaceName("rmnet0");
268        assertAllRoutesHaveInterface("rmnet0", lp);
269
270        // Now add a route with the wrong interface. This causes an exception too.
271        try {
272          lp.addRoute(r);
273          fail("Adding wlan0 route to rmnet0 LP, expect exception");
274        } catch (IllegalArgumentException expected) {}
275
276        // If the interface name matches, the route is added.
277        r = new RouteInfo(prefix, null, "wlan0");
278        lp.setInterfaceName("wlan0");
279        lp.addRoute(r);
280        assertEquals(2, lp.getRoutes().size());
281        assertAllRoutesHaveInterface("wlan0", lp);
282
283        // Routes with null interfaces are converted to wlan0.
284        r = RouteInfo.makeHostRoute(ADDRV6, null);
285        lp.addRoute(r);
286        assertEquals(3, lp.getRoutes().size());
287        assertAllRoutesHaveInterface("wlan0", lp);
288
289        // Check comparisons work.
290        LinkProperties lp2 = new LinkProperties(lp);
291        assertAllRoutesHaveInterface("wlan0", lp);
292        assertEquals(0, lp.compareAllRoutes(lp2).added.size());
293        assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
294
295        lp2.setInterfaceName("p2p0");
296        assertAllRoutesHaveInterface("p2p0", lp2);
297        assertEquals(3, lp.compareAllRoutes(lp2).added.size());
298        assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
299    }
300
301    @SmallTest
302    public void testStackedInterfaces() {
303        LinkProperties rmnet0 = new LinkProperties();
304        rmnet0.setInterfaceName("rmnet0");
305        rmnet0.addLinkAddress(LINKADDRV6);
306
307        LinkProperties clat4 = new LinkProperties();
308        clat4.setInterfaceName("clat4");
309        clat4.addLinkAddress(LINKADDRV4);
310
311        assertEquals(0, rmnet0.getStackedLinks().size());
312        assertEquals(1, rmnet0.getAddresses().size());
313        assertEquals(1, rmnet0.getLinkAddresses().size());
314        assertEquals(1, rmnet0.getAllAddresses().size());
315        assertEquals(1, rmnet0.getAllLinkAddresses().size());
316
317        rmnet0.addStackedLink(clat4);
318        assertEquals(1, rmnet0.getStackedLinks().size());
319        assertEquals(1, rmnet0.getAddresses().size());
320        assertEquals(1, rmnet0.getLinkAddresses().size());
321        assertEquals(2, rmnet0.getAllAddresses().size());
322        assertEquals(2, rmnet0.getAllLinkAddresses().size());
323
324        rmnet0.addStackedLink(clat4);
325        assertEquals(1, rmnet0.getStackedLinks().size());
326        assertEquals(1, rmnet0.getAddresses().size());
327        assertEquals(1, rmnet0.getLinkAddresses().size());
328        assertEquals(2, rmnet0.getAllAddresses().size());
329        assertEquals(2, rmnet0.getAllLinkAddresses().size());
330
331        assertEquals(0, clat4.getStackedLinks().size());
332
333        // Modify an item in the returned collection to see what happens.
334        for (LinkProperties link : rmnet0.getStackedLinks()) {
335            if (link.getInterfaceName().equals("clat4")) {
336               link.setInterfaceName("newname");
337            }
338        }
339        for (LinkProperties link : rmnet0.getStackedLinks()) {
340            assertFalse("newname".equals(link.getInterfaceName()));
341        }
342
343        assertTrue(rmnet0.removeStackedLink("clat4"));
344        assertEquals(0, rmnet0.getStackedLinks().size());
345        assertEquals(1, rmnet0.getAddresses().size());
346        assertEquals(1, rmnet0.getLinkAddresses().size());
347        assertEquals(1, rmnet0.getAllAddresses().size());
348        assertEquals(1, rmnet0.getAllLinkAddresses().size());
349
350        assertFalse(rmnet0.removeStackedLink("clat4"));
351    }
352
353    private LinkAddress getFirstLinkAddress(LinkProperties lp) {
354        return lp.getLinkAddresses().iterator().next();
355    }
356
357    @SmallTest
358    public void testAddressMethods() {
359        LinkProperties lp = new LinkProperties();
360
361        // No addresses.
362        assertFalse(lp.hasIPv4Address());
363        assertFalse(lp.hasGlobalIPv6Address());
364
365        // Addresses on stacked links don't count.
366        LinkProperties stacked = new LinkProperties();
367        stacked.setInterfaceName("stacked");
368        lp.addStackedLink(stacked);
369        stacked.addLinkAddress(LINKADDRV4);
370        stacked.addLinkAddress(LINKADDRV6);
371        assertTrue(stacked.hasIPv4Address());
372        assertTrue(stacked.hasGlobalIPv6Address());
373        assertFalse(lp.hasIPv4Address());
374        assertFalse(lp.hasGlobalIPv6Address());
375        lp.removeStackedLink("stacked");
376        assertFalse(lp.hasIPv4Address());
377        assertFalse(lp.hasGlobalIPv6Address());
378
379        // Addresses on the base link.
380        // Check the return values of hasIPvXAddress and ensure the add/remove methods return true
381        // iff something changes.
382        assertEquals(0, lp.getLinkAddresses().size());
383        assertTrue(lp.addLinkAddress(LINKADDRV6));
384        assertEquals(1, lp.getLinkAddresses().size());
385        assertFalse(lp.hasIPv4Address());
386        assertTrue(lp.hasGlobalIPv6Address());
387
388        assertTrue(lp.removeLinkAddress(LINKADDRV6));
389        assertEquals(0, lp.getLinkAddresses().size());
390
391        assertTrue(lp.addLinkAddress(LINKADDRV6LINKLOCAL));
392        assertEquals(1, lp.getLinkAddresses().size());
393        assertFalse(lp.hasGlobalIPv6Address());
394
395        assertTrue(lp.addLinkAddress(LINKADDRV4));
396        assertEquals(2, lp.getLinkAddresses().size());
397        assertTrue(lp.hasIPv4Address());
398        assertFalse(lp.hasGlobalIPv6Address());
399
400        assertTrue(lp.addLinkAddress(LINKADDRV6));
401        assertEquals(3, lp.getLinkAddresses().size());
402        assertTrue(lp.hasIPv4Address());
403        assertTrue(lp.hasGlobalIPv6Address());
404
405        assertTrue(lp.removeLinkAddress(LINKADDRV6LINKLOCAL));
406        assertEquals(2, lp.getLinkAddresses().size());
407        assertTrue(lp.hasIPv4Address());
408        assertTrue(lp.hasGlobalIPv6Address());
409
410        // Adding an address twice has no effect.
411        // Removing an address that's not present has no effect.
412        assertFalse(lp.addLinkAddress(LINKADDRV4));
413        assertEquals(2, lp.getLinkAddresses().size());
414        assertTrue(lp.hasIPv4Address());
415        assertTrue(lp.removeLinkAddress(LINKADDRV4));
416        assertEquals(1, lp.getLinkAddresses().size());
417        assertFalse(lp.hasIPv4Address());
418        assertFalse(lp.removeLinkAddress(LINKADDRV4));
419        assertEquals(1, lp.getLinkAddresses().size());
420
421        // Adding an address that's already present but with different properties causes the
422        // existing address to be updated and returns true.
423        // Start with only LINKADDRV6.
424        assertEquals(1, lp.getLinkAddresses().size());
425        assertEquals(LINKADDRV6, getFirstLinkAddress(lp));
426
427        // Create a LinkAddress object for the same address, but with different flags.
428        LinkAddress deprecated = new LinkAddress(ADDRV6, 128,
429                OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE);
430        assertTrue(deprecated.isSameAddressAs(LINKADDRV6));
431        assertFalse(deprecated.equals(LINKADDRV6));
432
433        // Check that adding it updates the existing address instead of adding a new one.
434        assertTrue(lp.addLinkAddress(deprecated));
435        assertEquals(1, lp.getLinkAddresses().size());
436        assertEquals(deprecated, getFirstLinkAddress(lp));
437        assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp)));
438
439        // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties.
440        assertTrue(lp.removeLinkAddress(LINKADDRV6));
441        assertEquals(0, lp.getLinkAddresses().size());
442    }
443
444    @SmallTest
445    public void testSetLinkAddresses() {
446        LinkProperties lp = new LinkProperties();
447        lp.addLinkAddress(LINKADDRV4);
448        lp.addLinkAddress(LINKADDRV6);
449
450        LinkProperties lp2 = new LinkProperties();
451        lp2.addLinkAddress(LINKADDRV6);
452
453        assertFalse(lp.equals(lp2));
454
455        lp2.setLinkAddresses(lp.getLinkAddresses());
456        assertTrue(lp.equals(lp));
457    }
458
459    @SmallTest
460    public void testIsProvisioned() {
461        LinkProperties lp4 = new LinkProperties();
462        assertFalse("v4only:empty", lp4.isProvisioned());
463        lp4.addLinkAddress(LINKADDRV4);
464        assertFalse("v4only:addr-only", lp4.isProvisioned());
465        lp4.addDnsServer(DNS1);
466        assertFalse("v4only:addr+dns", lp4.isProvisioned());
467        lp4.addRoute(new RouteInfo(GATEWAY1));
468        assertTrue("v4only:addr+dns+route", lp4.isProvisioned());
469
470        LinkProperties lp6 = new LinkProperties();
471        assertFalse("v6only:empty", lp6.isProvisioned());
472        lp6.addLinkAddress(LINKADDRV6LINKLOCAL);
473        assertFalse("v6only:fe80-only", lp6.isProvisioned());
474        lp6.addDnsServer(DNS6);
475        assertFalse("v6only:fe80+dns", lp6.isProvisioned());
476        lp6.addRoute(new RouteInfo(GATEWAY6));
477        assertFalse("v6only:fe80+dns+route", lp6.isProvisioned());
478        lp6.addLinkAddress(LINKADDRV6);
479        assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned());
480        lp6.removeLinkAddress(LINKADDRV6LINKLOCAL);
481        assertTrue("v6only:global+dns+route", lp6.isProvisioned());
482
483        LinkProperties lp46 = new LinkProperties();
484        lp46.addLinkAddress(LINKADDRV4);
485        lp46.addLinkAddress(LINKADDRV6);
486        lp46.addDnsServer(DNS1);
487        lp46.addDnsServer(DNS6);
488        assertFalse("dualstack:missing-routes", lp46.isProvisioned());
489        lp46.addRoute(new RouteInfo(GATEWAY1));
490        assertTrue("dualstack:v4-provisioned", lp46.isProvisioned());
491        lp6.addRoute(new RouteInfo(GATEWAY6));
492        assertTrue("dualstack:both-provisioned", lp46.isProvisioned());
493
494        // A link with an IPv6 address and default route, but IPv4 DNS server.
495        LinkProperties mixed = new LinkProperties();
496        mixed.addLinkAddress(LINKADDRV6);
497        mixed.addDnsServer(DNS1);
498        mixed.addRoute(new RouteInfo(GATEWAY6));
499        assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned());
500    }
501}
502