• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package java.net;
27 
28 import android.system.ErrnoException;
29 
30 import java.io.FileDescriptor;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.Enumeration;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.NoSuchElementException;
39 
40 import android.system.StructIfaddrs;
41 import libcore.io.IoUtils;
42 import libcore.io.Libcore;
43 import sun.security.action.*;
44 import java.security.AccessController;
45 
46 import static android.system.OsConstants.*;
47 
48 // Android-note: NetworkInterface has been rewritten to avoid native code.
49 // Fix upstream bug not returning link-down interfaces. http://b/26238832
50 // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
51 /**
52  * This class represents a Network Interface made up of a name,
53  * and a list of IP addresses assigned to this interface.
54  * It is used to identify the local interface on which a multicast group
55  * is joined.
56  *
57  * Interfaces are normally known by names such as "le0".
58  * <p>
59  * <a name="access-restrictions"></a>Note that information about
60  * {@link NetworkInterface}s may be restricted. For example, non-system apps
61  * with {@code targetSdkVersion >= android.os.Build.VERSION_CODES.R} will only
62  * have access to information about {@link NetworkInterface}s that are
63  * associated with an {@link InetAddress}.
64  *
65  * @since 1.4
66  */
67 public final class NetworkInterface {
68     private String name;
69     private String displayName;
70     private int index;
71     private InetAddress addrs[];
72     private InterfaceAddress bindings[];
73     // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
74     // private NetworkInterface childs[];
75     private List<NetworkInterface> childs;
76     private NetworkInterface parent = null;
77     private boolean virtual = false;
78     private static final NetworkInterface defaultInterface;
79     private static final int defaultIndex; /* index of defaultInterface */
80 
81     // Android-changed: Fix upstream bug not returning link-down interfaces. http://b/26238832
82     private byte[] hardwareAddr;
83 
84     static {
85         // Android-removed: Android doesn't need to call native init.
86         /*
87         AccessController.doPrivileged(
88             new java.security.PrivilegedAction<Void>() {
89                 public Void run() {
90                     System.loadLibrary("net");
91                     return null;
92                 }
93             });
94 
95         init();
96         */
97         defaultInterface = DefaultInterface.getDefault();
98         if (defaultInterface != null) {
99             defaultIndex = defaultInterface.getIndex();
100         } else {
101             defaultIndex = 0;
102         }
103     }
104 
105     /**
106      * Returns an NetworkInterface object with index set to 0 and name to null.
107      * Setting such an interface on a MulticastSocket will cause the
108      * kernel to choose one interface for sending multicast packets.
109      *
110      */
NetworkInterface()111     NetworkInterface() {
112     }
113 
NetworkInterface(String name, int index, InetAddress[] addrs)114     NetworkInterface(String name, int index, InetAddress[] addrs) {
115         this.name = name;
116         this.index = index;
117         this.addrs = addrs;
118     }
119 
120     /**
121      * Get the name of this network interface.
122      *
123      * @return the name of this network interface
124      */
getName()125     public String getName() {
126             return name;
127     }
128 
129     /**
130      * Convenience method to return an Enumeration with all or a
131      * subset of the InetAddresses bound to this network interface.
132      * <p>
133      * If there is a security manager, its {@code checkConnect}
134      * method is called for each InetAddress. Only InetAddresses where
135      * the {@code checkConnect} doesn't throw a SecurityException
136      * will be returned in the Enumeration. However, if the caller has the
137      * {@link NetPermission}("getNetworkInformation") permission, then all
138      * InetAddresses are returned.
139      * @return an Enumeration object with all or a subset of the InetAddresses
140      * bound to this network interface
141      */
getInetAddresses()142     public Enumeration<InetAddress> getInetAddresses() {
143 
144         class checkedAddresses implements Enumeration<InetAddress> {
145 
146             private int i=0, count=0;
147             private InetAddress local_addrs[];
148 
149             checkedAddresses() {
150                 local_addrs = new InetAddress[addrs.length];
151                 boolean trusted = true;
152 
153                 SecurityManager sec = System.getSecurityManager();
154                 if (sec != null) {
155                     try {
156                         sec.checkPermission(new NetPermission("getNetworkInformation"));
157                     } catch (SecurityException e) {
158                         trusted = false;
159                     }
160                 }
161                 for (int j=0; j<addrs.length; j++) {
162                     try {
163                         if (sec != null && !trusted) {
164                             sec.checkConnect(addrs[j].getHostAddress(), -1);
165                         }
166                         local_addrs[count++] = addrs[j];
167                     } catch (SecurityException e) { }
168                 }
169 
170             }
171 
172             public InetAddress nextElement() {
173                 if (i < count) {
174                     return local_addrs[i++];
175                 } else {
176                     throw new NoSuchElementException();
177                 }
178             }
179 
180             public boolean hasMoreElements() {
181                 return (i < count);
182             }
183         }
184         return new checkedAddresses();
185 
186     }
187 
188     /**
189      * Get a List of all or a subset of the {@code InterfaceAddresses}
190      * of this network interface.
191      * <p>
192      * If there is a security manager, its {@code checkConnect}
193      * method is called with the InetAddress for each InterfaceAddress.
194      * Only InterfaceAddresses where the {@code checkConnect} doesn't throw
195      * a SecurityException will be returned in the List.
196      *
197      * @return a {@code List} object with all or a subset of the
198      *         InterfaceAddresss of this network interface
199      * @since 1.6
200      */
getInterfaceAddresses()201     public java.util.List<InterfaceAddress> getInterfaceAddresses() {
202         java.util.List<InterfaceAddress> lst = new java.util.ArrayList<InterfaceAddress>(1);
203         // BEGIN Android-changed: Cherry-picked upstream OpenJDK9 change rev 59a110a38cea
204         // http://b/30628919
205         if (bindings != null) {
206             SecurityManager sec = System.getSecurityManager();
207             for (int j=0; j<bindings.length; j++) {
208                 try {
209                     if (sec != null) {
210                         sec.checkConnect(bindings[j].getAddress().getHostAddress(), -1);
211                     }
212                     lst.add(bindings[j]);
213                 } catch (SecurityException e) { }
214             }
215         }
216         // END Android-changed: Cherry-picked upstream OpenJDK9 change rev 59a110a38cea
217         return lst;
218     }
219 
220     /**
221      * Get an Enumeration with all the subinterfaces (also known as virtual
222      * interfaces) attached to this network interface.
223      * <p>
224      * For instance eth0:1 will be a subinterface to eth0.
225      *
226      * @return an Enumeration object with all of the subinterfaces
227      * of this network interface
228      * @since 1.6
229      */
getSubInterfaces()230     public Enumeration<NetworkInterface> getSubInterfaces() {
231         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
232         return Collections.enumeration(childs);
233     }
234 
235     /**
236      * Returns the parent NetworkInterface of this interface if this is
237      * a subinterface, or {@code null} if it is a physical
238      * (non virtual) interface or has no parent.
239      *
240      * @return The {@code NetworkInterface} this interface is attached to.
241      * @since 1.6
242      */
getParent()243     public NetworkInterface getParent() {
244         return parent;
245     }
246 
247     /**
248      * Returns the index of this network interface. The index is an integer greater
249      * or equal to zero, or {@code -1} for unknown. This is a system specific value
250      * and interfaces with the same name can have different indexes on different
251      * machines.
252      *
253      * @return the index of this network interface or {@code -1} if the index is
254      *         unknown
255      * @see #getByIndex(int)
256      * @since 1.7
257      */
getIndex()258     public int getIndex() {
259         return index;
260     }
261 
262     /**
263      * Get the display name of this network interface.
264      * A display name is a human readable String describing the network
265      * device.
266      *
267      * @return a non-empty string representing the display name of this network
268      *         interface, or null if no display name is available.
269      */
getDisplayName()270     public String getDisplayName() {
271         /* strict TCK conformance */
272         return "".equals(displayName) ? null : displayName;
273     }
274 
275     // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
276     /**
277      * Searches for the network interface with the specified name.
278      *
279      * @param   name
280      *          The name of the network interface.
281      *
282      * @return  A {@code NetworkInterface} with the specified name,
283      *          or {@code null} if the network interface with the specified
284      *          name does not exist or <a href="#access-restrictions">can't be
285      *          accessed</a>.
286      *
287      * @throws  SocketException
288      *          If an I/O error occurs.
289      *
290      * @throws  NullPointerException
291      *          If the specified name is {@code null}.
292      */
getByName(String name)293     public static NetworkInterface getByName(String name) throws SocketException {
294         if (name == null)
295             throw new NullPointerException();
296 
297         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
298         NetworkInterface[] nis = getAll();
299         for (NetworkInterface ni : nis) {
300             if (ni.getName().equals(name)) {
301                 return ni;
302             }
303         }
304         return null;
305     }
306 
307     // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
308     /**
309      * Get a network interface given its index.
310      *
311      * @param index an integer, the index of the interface
312      * @return the NetworkInterface obtained from its index, or {@code null} if
313      *         an interface with the specified index does not exist or
314      *         <a href="#access-restrictions">can't be accessed</a>.
315      * @throws  SocketException  if an I/O error occurs.
316      * @throws  IllegalArgumentException if index has a negative value
317      * @see #getIndex()
318      * @since 1.7
319      */
getByIndex(int index)320     public static NetworkInterface getByIndex(int index) throws SocketException {
321         if (index < 0)
322             throw new IllegalArgumentException("Interface index can't be negative");
323 
324         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
325         NetworkInterface[] nis = getAll();
326         for (NetworkInterface ni : nis) {
327             if (ni.getIndex() == index) {
328                 return ni;
329             }
330         }
331         return null;
332     }
333 
334     /**
335      * Convenience method to search for a network interface that
336      * has the specified Internet Protocol (IP) address bound to
337      * it.
338      * <p>
339      * If the specified IP address is bound to multiple network
340      * interfaces it is not defined which network interface is
341      * returned.
342      *
343      * @param   addr
344      *          The {@code InetAddress} to search with.
345      *
346      * @return  A {@code NetworkInterface}
347      *          or {@code null} if there is no network interface
348      *          with the specified IP address.
349      *
350      * @throws  SocketException
351      *          If an I/O error occurs.
352      *
353      * @throws  NullPointerException
354      *          If the specified address is {@code null}.
355      */
getByInetAddress(InetAddress addr)356     public static NetworkInterface getByInetAddress(InetAddress addr) throws SocketException {
357         if (addr == null) {
358             throw new NullPointerException();
359         }
360         if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
361             throw new IllegalArgumentException ("invalid address type");
362         }
363 
364         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
365         NetworkInterface[] nis = getAll();
366         for (NetworkInterface ni : nis) {
367             for (InetAddress inetAddress : Collections.list(ni.getInetAddresses())) {
368                 if (inetAddress.equals(addr)) {
369                     return ni;
370                 }
371             }
372         }
373         return null;
374     }
375 
376     // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
377     /**
378      * Returns all the interfaces on this machine. The {@code Enumeration}
379      * contains at least one element, possibly representing a loopback
380      * interface that only supports communication between entities on
381      * this machine.
382      *
383      * NOTE: can use getNetworkInterfaces()+getInetAddresses()
384      *       to obtain all IP addresses for this node
385      * <p>
386      * For non-system apps with
387      * {@code targetSdkVersion >= android.os.Build.VERSION_CODES.R}, this
388      * method will only return information for {@link NetworkInterface}s that
389      * are associated with an {@link InetAddress}.
390      *
391      * @return an Enumeration of NetworkInterfaces found on this machine
392      *         that <a href="#access-restrictions">are accessible</a>.
393      * @exception  SocketException  if an I/O error occurs.
394      */
395 
getNetworkInterfaces()396     public static Enumeration<NetworkInterface> getNetworkInterfaces()
397         throws SocketException {
398         final NetworkInterface[] netifs = getAll();
399         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
400         // // specified to return null if no network interfaces
401         // if (netifs == null)
402         if (netifs.length == 0)
403             return null;
404 
405         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
406         /*
407         return new Enumeration<NetworkInterface>() {
408             private int i = 0;
409             public NetworkInterface nextElement() {
410                 if (netifs != null && i < netifs.length) {
411                     NetworkInterface netif = netifs[i++];
412                     return netif;
413                 } else {
414                     throw new NoSuchElementException();
415                 }
416             }
417 
418             public boolean hasMoreElements() {
419                 return (netifs != null && i < netifs.length);
420             }
421         };
422         */
423         return Collections.enumeration(Arrays.asList(netifs));
424     }
425 
426     // BEGIN Android-changed: Rewrote NetworkInterface on top of Libcore.io.
427     // private native static NetworkInterface[] getAll()
428     //    throws SocketException;
getAll()429     private static NetworkInterface[] getAll() throws SocketException {
430         // Group Ifaddrs by interface name.
431         Map<String, List<StructIfaddrs>> inetMap = new HashMap<>();
432 
433         StructIfaddrs[] ifaddrs;
434         try {
435             ifaddrs = Libcore.os.getifaddrs();
436         } catch (ErrnoException e) {
437             throw e.rethrowAsSocketException();
438         }
439 
440         for (StructIfaddrs ifa : ifaddrs) {
441             String name = ifa.ifa_name;
442 
443             List<StructIfaddrs> ifas;
444             if ((ifas = inetMap.get(name)) == null) {
445                 ifas = new ArrayList<>();
446                 inetMap.put(name, ifas);
447             }
448 
449             ifas.add(ifa);
450         }
451 
452         // Populate NetworkInterface instances.
453         Map<String, NetworkInterface> nis = new HashMap<>(inetMap.size());
454         for (Map.Entry<String, List<StructIfaddrs>> e : inetMap.entrySet()) {
455             String name = e.getKey();
456             int index = Libcore.os.if_nametoindex(e.getKey());
457             if (index == 0) {
458                 // This interface has gone away between getifaddrs and if_nametoindex
459                 continue;
460             }
461 
462             NetworkInterface ni = new NetworkInterface(name, index, null);
463             ni.displayName = name;
464 
465             List<InetAddress> addrs = new ArrayList<>();
466             List<InterfaceAddress> binds = new ArrayList<>();
467 
468             for (StructIfaddrs ifa : e.getValue()) {
469                 if (ifa.ifa_addr != null) {
470                     addrs.add(ifa.ifa_addr);
471                     binds.add(new InterfaceAddress(ifa.ifa_addr, (Inet4Address) ifa.ifa_broadaddr,
472                                                    ifa.ifa_netmask));
473                 }
474 
475                 if (ifa.hwaddr != null) {
476                     ni.hardwareAddr = ifa.hwaddr;
477                 }
478             }
479 
480             ni.addrs = addrs.toArray(new InetAddress[addrs.size()]);
481             ni.bindings = binds.toArray(new InterfaceAddress[binds.size()]);
482             ni.childs = new ArrayList<>(0);
483             nis.put(name, ni);
484         }
485 
486         // Populate childs/parent.
487         for (Map.Entry<String, NetworkInterface> e : nis.entrySet()) {
488             NetworkInterface ni = e.getValue();
489             String niName = ni.getName();
490             int colonIdx = niName.indexOf(':');
491             if (colonIdx != -1) {
492                 // This is a virtual interface.
493                 String parentName = niName.substring(0, colonIdx);
494                 NetworkInterface parent = nis.get(parentName);
495 
496                 ni.virtual = true;
497 
498                 if (parent != null) {
499                     ni.parent = parent;
500                     parent.childs.add(ni);
501                 }
502             }
503         }
504 
505         return nis.values().toArray(new NetworkInterface[nis.size()]);
506     }
507     // END Android-changed: Rewrote NetworkInterface on top of Libcore.io.
508 
509     /**
510      * Returns whether a network interface is up and running.
511      *
512      * @return  {@code true} if the interface is up and running.
513      * @exception       SocketException if an I/O error occurs.
514      * @since 1.6
515      */
516 
isUp()517     public boolean isUp() throws SocketException {
518         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
519         final int mask = IFF_UP | IFF_RUNNING;
520         return (getFlags() & mask) == mask;
521     }
522 
523     /**
524      * Returns whether a network interface is a loopback interface.
525      *
526      * @return  {@code true} if the interface is a loopback interface.
527      * @exception       SocketException if an I/O error occurs.
528      * @since 1.6
529      */
530 
isLoopback()531     public boolean isLoopback() throws SocketException {
532         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
533         return (getFlags() & IFF_LOOPBACK) != 0;
534     }
535 
536     /**
537      * Returns whether a network interface is a point to point interface.
538      * A typical point to point interface would be a PPP connection through
539      * a modem.
540      *
541      * @return  {@code true} if the interface is a point to point
542      *          interface.
543      * @exception       SocketException if an I/O error occurs.
544      * @since 1.6
545      */
546 
isPointToPoint()547     public boolean isPointToPoint() throws SocketException {
548         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
549         return (getFlags() & IFF_POINTOPOINT) != 0;
550     }
551 
552     /**
553      * Returns whether a network interface supports multicasting or not.
554      *
555      * @return  {@code true} if the interface supports Multicasting.
556      * @exception       SocketException if an I/O error occurs.
557      * @since 1.6
558      */
559 
supportsMulticast()560     public boolean supportsMulticast() throws SocketException {
561         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
562         return (getFlags() & IFF_MULTICAST) != 0;
563     }
564 
565     // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
566     /**
567      * Returns the hardware address (usually MAC) of the interface if it
568      * has one and if it can be accessed given the current privileges.
569      * If a security manager is set, then the caller must have
570      * the permission {@link NetPermission}("getNetworkInformation").
571      *
572      * @return  a byte array containing the address, or {@code null} if
573      *          the address doesn't exist, is not accessible or a security
574      *          manager is set and the caller does not have the permission
575      *          NetPermission("getNetworkInformation"). For example, this
576      *          method will generally return {@code null} when called by
577      *          non-system apps having
578      *          {@code targetSdkVersion >= android.os.Build.VERSION_CODES.R}.
579      *
580      * @exception       SocketException if an I/O error occurs.
581      * @since 1.6
582      */
getHardwareAddress()583     public byte[] getHardwareAddress() throws SocketException {
584         // BEGIN Android-changed: Fix upstream not returning link-down interfaces. http://b/26238832
585         /*
586         for (InetAddress addr : addrs) {
587             if (addr instanceof Inet4Address) {
588                 return getMacAddr0(((Inet4Address)addr).getAddress(), name, index);
589             }
590         }
591         return getMacAddr0(null, name, index);
592          */
593         NetworkInterface ni = getByName(name);
594         if (ni == null) {
595             throw new SocketException("NetworkInterface doesn't exist anymore");
596         }
597         return ni.hardwareAddr;
598         // END Android-changed: Fix upstream not returning link-down interfaces. http://b/26238832
599     }
600 
601     /**
602      * Returns the Maximum Transmission Unit (MTU) of this interface.
603      *
604      * @return the value of the MTU for that interface.
605      * @exception       SocketException if an I/O error occurs.
606      * @since 1.6
607      */
getMTU()608     public int getMTU() throws SocketException {
609         // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
610         // return getMTU0(name, index);
611         FileDescriptor fd = null;
612         try {
613             fd = Libcore.rawOs.socket(AF_INET, SOCK_DGRAM, 0);
614             return Libcore.rawOs.ioctlMTU(fd, name);
615         } catch (ErrnoException e) {
616             throw e.rethrowAsSocketException();
617         } catch (Exception ex) {
618             throw new SocketException(ex);
619         } finally {
620             IoUtils.closeQuietly(fd);
621         }
622     }
623 
624     /**
625      * Returns whether this interface is a virtual interface (also called
626      * subinterface).
627      * Virtual interfaces are, on some systems, interfaces created as a child
628      * of a physical interface and given different settings (like address or
629      * MTU). Usually the name of the interface will the name of the parent
630      * followed by a colon (:) and a number identifying the child since there
631      * can be several virtual interfaces attached to a single physical
632      * interface.
633      *
634      * @return {@code true} if this interface is a virtual interface.
635      * @since 1.6
636      */
isVirtual()637     public boolean isVirtual() {
638         return virtual;
639     }
640 
641     // BEGIN Android-removed: Rewrote NetworkInterface on top of Libcore.io.
642     /*
643     private native static boolean isUp0(String name, int ind) throws SocketException;
644     private native static boolean isLoopback0(String name, int ind) throws SocketException;
645     private native static boolean supportsMulticast0(String name, int ind) throws SocketException;
646     private native static boolean isP2P0(String name, int ind) throws SocketException;
647     private native static byte[] getMacAddr0(byte[] inAddr, String name, int ind) throws SocketException;
648     private native static int getMTU0(String name, int ind) throws SocketException;
649     */
650     // END Android-removed: Rewrote NetworkInterface on top of Libcore.io.
651 
652     // BEGIN Android-added: Rewrote NetworkInterface on top of Libcore.io.
getFlags()653     private int getFlags() throws SocketException {
654         FileDescriptor fd = null;
655         try {
656             fd = Libcore.rawOs.socket(AF_INET, SOCK_DGRAM, 0);
657             return Libcore.rawOs.ioctlFlags(fd, name);
658         } catch (ErrnoException e) {
659             throw e.rethrowAsSocketException();
660         } catch (Exception ex) {
661             throw new SocketException(ex);
662         } finally {
663             IoUtils.closeQuietly(fd);
664         }
665     }
666     // END Android-added: Rewrote NetworkInterface on top of Libcore.io.
667 
668     /**
669      * Compares this object against the specified object.
670      * The result is {@code true} if and only if the argument is
671      * not {@code null} and it represents the same NetworkInterface
672      * as this object.
673      * <p>
674      * Two instances of {@code NetworkInterface} represent the same
675      * NetworkInterface if both name and addrs are the same for both.
676      *
677      * @param   obj   the object to compare against.
678      * @return  {@code true} if the objects are the same;
679      *          {@code false} otherwise.
680      * @see     java.net.InetAddress#getAddress()
681      */
equals(Object obj)682     public boolean equals(Object obj) {
683         if (!(obj instanceof NetworkInterface)) {
684             return false;
685         }
686         NetworkInterface that = (NetworkInterface)obj;
687         if (this.name != null ) {
688             if (!this.name.equals(that.name)) {
689                 return false;
690             }
691         } else {
692             if (that.name != null) {
693                 return false;
694             }
695         }
696 
697         if (this.addrs == null) {
698             return that.addrs == null;
699         } else if (that.addrs == null) {
700             return false;
701         }
702 
703         /* Both addrs not null. Compare number of addresses */
704 
705         if (this.addrs.length != that.addrs.length) {
706             return false;
707         }
708 
709         InetAddress[] thatAddrs = that.addrs;
710         int count = thatAddrs.length;
711 
712         for (int i=0; i<count; i++) {
713             boolean found = false;
714             for (int j=0; j<count; j++) {
715                 if (addrs[i].equals(thatAddrs[j])) {
716                     found = true;
717                     break;
718                 }
719             }
720             if (!found) {
721                 return false;
722             }
723         }
724         return true;
725     }
726 
hashCode()727     public int hashCode() {
728         return name == null? 0: name.hashCode();
729     }
730 
toString()731     public String toString() {
732         String result = "name:";
733         result += name == null? "null": name;
734         if (displayName != null) {
735             result += " (" + displayName + ")";
736         }
737         return result;
738     }
739 
740     // Android-removed: Android doesn't need to call native init.
741     // private static native void init();
742 
743     /**
744      * Returns the default network interface of this system
745      *
746      * @return the default interface
747      */
getDefault()748     static NetworkInterface getDefault() {
749         return defaultInterface;
750     }
751 }
752