1/*
2 * Copyright (c) 2000, 2017, 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#include <arpa/inet.h>
26#include <errno.h>
27#include <net/if.h>
28#include <net/if_arp.h>
29#include <stdlib.h>
30#include <string.h>
31#include <sys/ioctl.h>
32
33#if defined(_AIX)
34#include <netinet/in6_var.h>
35#include <sys/ndd_var.h>
36#include <sys/kinfo.h>
37#endif
38
39#if defined(__solaris__)
40#include <stropts.h>
41#include <sys/dlpi.h>
42#include <sys/sockio.h>
43#endif
44
45#if defined(_ALLBSD_SOURCE)
46#include <net/ethernet.h>
47#include <net/if_dl.h>
48#include <ifaddrs.h>
49#endif
50
51#include "net_util.h"
52
53#include "java_net_InetAddress.h"
54
55#if defined(__linux__)
56    #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
57#elif defined(__solaris__)
58    #ifndef SIOCGLIFHWADDR
59        #define SIOCGLIFHWADDR _IOWR('i', 192, struct lifreq)
60    #endif
61    #define DEV_PREFIX "/dev/"
62#endif
63
64#ifdef LIFNAMSIZ
65    #define IFNAMESIZE LIFNAMSIZ
66#else
67    #define IFNAMESIZE IFNAMSIZ
68#endif
69
70#define CHECKED_MALLOC3(_pointer, _type, _size) \
71    do { \
72        _pointer = (_type)malloc(_size); \
73        if (_pointer == NULL) { \
74            JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \
75            return ifs; /* return untouched list */ \
76        } \
77    } while(0)
78
79typedef struct _netaddr  {
80    struct sockaddr *addr;
81    struct sockaddr *brdcast;
82    short mask;
83    int family; /* to make searches simple */
84    struct _netaddr *next;
85} netaddr;
86
87typedef struct _netif {
88    char *name;
89    int index;
90    char virtual;
91    netaddr *addr;
92    struct _netif *childs;
93    struct _netif *next;
94} netif;
95
96/************************************************************************
97 * NetworkInterface
98 */
99
100#include "java_net_NetworkInterface.h"
101
102/************************************************************************
103 * NetworkInterface
104 */
105jclass ni_class;
106jfieldID ni_nameID;
107jfieldID ni_indexID;
108jfieldID ni_descID;
109jfieldID ni_addrsID;
110jfieldID ni_bindsID;
111jfieldID ni_virutalID;
112jfieldID ni_childsID;
113jfieldID ni_parentID;
114jfieldID ni_defaultIndexID;
115jmethodID ni_ctrID;
116
117static jclass ni_ibcls;
118static jmethodID ni_ibctrID;
119static jfieldID ni_ibaddressID;
120static jfieldID ni_ib4broadcastID;
121static jfieldID ni_ib4maskID;
122
123/** Private methods declarations **/
124static jobject createNetworkInterface(JNIEnv *env, netif *ifs);
125static int     getFlags0(JNIEnv *env, jstring  ifname);
126
127static netif  *enumInterfaces(JNIEnv *env);
128static netif  *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs);
129static netif  *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs);
130
131static netif  *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,
132                     struct sockaddr *ifr_addrP,
133                     struct sockaddr *ifr_broadaddrP,
134                     int family, short prefix);
135static void    freeif(netif *ifs);
136
137static int     openSocket(JNIEnv *env, int proto);
138static int     openSocketWithFallback(JNIEnv *env, const char *ifname);
139
140static short   translateIPv4AddressToPrefix(struct sockaddr_in *addr);
141static short   translateIPv6AddressToPrefix(struct sockaddr_in6 *addr);
142
143static int     getIndex(int sock, const char *ifname);
144static int     getFlags(int sock, const char *ifname, int *flags);
145static int     getMacAddress(JNIEnv *env, const char *ifname,
146                             const struct in_addr *addr, unsigned char *buf);
147static int     getMTU(JNIEnv *env, int sock, const char *ifname);
148
149#if defined(__solaris__)
150static int     getMacFromDevice(JNIEnv *env, const char *ifname,
151                                unsigned char *retbuf);
152#endif
153
154/******************* Java entry points *****************************/
155
156/*
157 * Class:     java_net_NetworkInterface
158 * Method:    init
159 * Signature: ()V
160 */
161JNIEXPORT void JNICALL Java_java_net_NetworkInterface_init
162  (JNIEnv *env, jclass cls)
163{
164    ni_class = (*env)->FindClass(env, "java/net/NetworkInterface");
165    CHECK_NULL(ni_class);
166    ni_class = (*env)->NewGlobalRef(env, ni_class);
167    CHECK_NULL(ni_class);
168    ni_nameID = (*env)->GetFieldID(env, ni_class, "name", "Ljava/lang/String;");
169    CHECK_NULL(ni_nameID);
170    ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
171    CHECK_NULL(ni_indexID);
172    ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs",
173                                    "[Ljava/net/InetAddress;");
174    CHECK_NULL(ni_addrsID);
175    ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings",
176                                    "[Ljava/net/InterfaceAddress;");
177    CHECK_NULL(ni_bindsID);
178    ni_descID = (*env)->GetFieldID(env, ni_class, "displayName",
179                                   "Ljava/lang/String;");
180    CHECK_NULL(ni_descID);
181    ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z");
182    CHECK_NULL(ni_virutalID);
183    ni_childsID = (*env)->GetFieldID(env, ni_class, "childs",
184                                     "[Ljava/net/NetworkInterface;");
185    CHECK_NULL(ni_childsID);
186    ni_parentID = (*env)->GetFieldID(env, ni_class, "parent",
187                                     "Ljava/net/NetworkInterface;");
188    CHECK_NULL(ni_parentID);
189    ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
190    CHECK_NULL(ni_ctrID);
191    ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
192    CHECK_NULL(ni_ibcls);
193    ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
194    CHECK_NULL(ni_ibcls);
195    ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
196    CHECK_NULL(ni_ibctrID);
197    ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address",
198                                        "Ljava/net/InetAddress;");
199    CHECK_NULL(ni_ibaddressID);
200    ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast",
201                                           "Ljava/net/Inet4Address;");
202    CHECK_NULL(ni_ib4broadcastID);
203    ni_ib4maskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
204    CHECK_NULL(ni_ib4maskID);
205    ni_defaultIndexID = (*env)->GetStaticFieldID(env, ni_class, "defaultIndex",
206                                                 "I");
207    CHECK_NULL(ni_defaultIndexID);
208    initInetAddressIDs(env);
209}
210
211/*
212 * Class:     java_net_NetworkInterface
213 * Method:    getByName0
214 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
215 */
216JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0
217  (JNIEnv *env, jclass cls, jstring name)
218{
219    netif *ifs, *curr;
220    jboolean isCopy;
221    const char* name_utf;
222    char *colonP;
223    char searchName[IFNAMESIZE];
224    jobject obj = NULL;
225
226    if (name != NULL) {
227        name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
228    } else {
229        JNU_ThrowNullPointerException(env, "network interface name is NULL");
230        return NULL;
231    }
232
233    if (name_utf == NULL) {
234        if (!(*env)->ExceptionCheck(env))
235            JNU_ThrowOutOfMemoryError(env, NULL);
236        return NULL;
237    }
238
239    ifs = enumInterfaces(env);
240    if (ifs == NULL) {
241        return NULL;
242    }
243
244    // search the list of interfaces based on name,
245    // if it is virtual sub interface search with parent first.
246    strncpy(searchName, name_utf, IFNAMESIZE);
247    searchName[IFNAMESIZE - 1] = '\0';
248    colonP = strchr(searchName, ':');
249    if (colonP != NULL) {
250        *colonP = '\0';
251    }
252    curr = ifs;
253    while (curr != NULL) {
254        if (strcmp(searchName, curr->name) == 0) {
255            break;
256        }
257        curr = curr->next;
258    }
259
260    // search the child list
261    if (colonP != NULL && curr != NULL) {
262        curr = curr->childs;
263        while (curr != NULL) {
264            if (strcmp(name_utf, curr->name) == 0) {
265                break;
266            }
267            curr = curr->next;
268        }
269    }
270
271    // if found create a NetworkInterface
272    if (curr != NULL) {
273        obj = createNetworkInterface(env, curr);
274    }
275
276    // release the UTF string and interface list
277    (*env)->ReleaseStringUTFChars(env, name, name_utf);
278    freeif(ifs);
279
280    return obj;
281}
282
283/*
284 * Class:     java_net_NetworkInterface
285 * Method:    getByIndex0
286 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
287 */
288JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0
289  (JNIEnv *env, jclass cls, jint index)
290{
291    netif *ifs, *curr;
292    jobject obj = NULL;
293
294    if (index <= 0) {
295        return NULL;
296    }
297
298    ifs = enumInterfaces(env);
299    if (ifs == NULL) {
300        return NULL;
301    }
302
303    // search the list of interfaces based on index
304    curr = ifs;
305    while (curr != NULL) {
306        if (index == curr->index) {
307            break;
308        }
309        curr = curr->next;
310    }
311
312    // if found create a NetworkInterface
313    if (curr != NULL) {
314        obj = createNetworkInterface(env, curr);
315    }
316
317    // release the interface list
318    freeif(ifs);
319
320    return obj;
321}
322
323/*
324 * Class:     java_net_NetworkInterface
325 * Method:    getByInetAddress0
326 * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
327 */
328JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
329  (JNIEnv *env, jclass cls, jobject iaObj)
330{
331    netif *ifs, *curr;
332    int family = (getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4) ?
333        AF_INET : AF_INET6;
334    jobject obj = NULL;
335    jboolean match = JNI_FALSE;
336
337    ifs = enumInterfaces(env);
338    if (ifs == NULL) {
339        return NULL;
340    }
341
342    curr = ifs;
343    while (curr != NULL) {
344        netaddr *addrP = curr->addr;
345
346        // iterate through each address on the interface
347        while (addrP != NULL) {
348
349            if (family == addrP->family) {
350                if (family == AF_INET) {
351                    int address1 = htonl(
352                        ((struct sockaddr_in *)addrP->addr)->sin_addr.s_addr);
353                    int address2 = getInetAddress_addr(env, iaObj);
354
355                    if (address1 == address2) {
356                        match = JNI_TRUE;
357                        break;
358                    }
359                } else if (family == AF_INET6) {
360                    jbyte *bytes = (jbyte *)&(
361                        ((struct sockaddr_in6*)addrP->addr)->sin6_addr);
362                    jbyte caddr[16];
363                    int i;
364                    getInet6Address_ipaddress(env, iaObj, (char *)caddr);
365                    i = 0;
366                    while (i < 16) {
367                        if (caddr[i] != bytes[i]) {
368                            break;
369                        }
370                        i++;
371                    }
372                    if (i >= 16) {
373                        match = JNI_TRUE;
374                        break;
375                    }
376                }
377            }
378
379            if (match) {
380                break;
381            }
382            addrP = addrP->next;
383        }
384
385        if (match) {
386            break;
387        }
388        curr = curr->next;
389    }
390
391    // if found create a NetworkInterface
392    if (match) {
393        obj = createNetworkInterface(env, curr);
394    }
395
396    // release the interface list
397    freeif(ifs);
398
399    return obj;
400}
401
402/*
403 * Class:     java_net_NetworkInterface
404 * Method:    getAll
405 * Signature: ()[Ljava/net/NetworkInterface;
406 */
407JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll
408  (JNIEnv *env, jclass cls)
409{
410    netif *ifs, *curr;
411    jobjectArray netIFArr;
412    jint arr_index, ifCount;
413
414    ifs = enumInterfaces(env);
415    if (ifs == NULL) {
416        return NULL;
417    }
418
419    // count the interfaces
420    ifCount = 0;
421    curr = ifs;
422    while (curr != NULL) {
423        ifCount++;
424        curr = curr->next;
425    }
426
427    // allocate a NetworkInterface array
428    netIFArr = (*env)->NewObjectArray(env, ifCount, cls, NULL);
429    if (netIFArr == NULL) {
430        freeif(ifs);
431        return NULL;
432    }
433
434    // iterate through the interfaces, create a NetworkInterface instance
435    // for each array element and populate the object
436    curr = ifs;
437    arr_index = 0;
438    while (curr != NULL) {
439        jobject netifObj;
440
441        netifObj = createNetworkInterface(env, curr);
442        if (netifObj == NULL) {
443            freeif(ifs);
444            return NULL;
445        }
446
447        // put the NetworkInterface into the array
448        (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
449
450        curr = curr->next;
451    }
452
453    // release the interface list
454    freeif(ifs);
455
456    return netIFArr;
457}
458
459/*
460 * Class:     java_net_NetworkInterface
461 * Method:    isUp0
462 * Signature: (Ljava/lang/String;I)Z
463 */
464JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0
465  (JNIEnv *env, jclass cls, jstring name, jint index)
466{
467    int ret = getFlags0(env, name);
468    return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE :  JNI_FALSE;
469}
470
471/*
472 * Class:     java_net_NetworkInterface
473 * Method:    isP2P0
474 * Signature: (Ljava/lang/String;I)Z
475 */
476JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0
477  (JNIEnv *env, jclass cls, jstring name, jint index)
478{
479    int ret = getFlags0(env, name);
480    return (ret & IFF_POINTOPOINT) ? JNI_TRUE :  JNI_FALSE;
481}
482
483/*
484 * Class:     java_net_NetworkInterface
485 * Method:    isLoopback0
486 * Signature: (Ljava/lang/String;I)Z
487 */
488JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0
489  (JNIEnv *env, jclass cls, jstring name, jint index)
490{
491    int ret = getFlags0(env, name);
492    return (ret & IFF_LOOPBACK) ? JNI_TRUE :  JNI_FALSE;
493}
494
495/*
496 * Class:     java_net_NetworkInterface
497 * Method:    supportsMulticast0
498 * Signature: (Ljava/lang/String;I)Z
499 */
500JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0
501  (JNIEnv *env, jclass cls, jstring name, jint index)
502{
503    int ret = getFlags0(env, name);
504    return (ret & IFF_MULTICAST) ? JNI_TRUE :  JNI_FALSE;
505}
506
507/*
508 * Class:     java_net_NetworkInterface
509 * Method:    getMacAddr0
510 * Signature: ([bLjava/lang/String;I)[b
511 */
512JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0
513  (JNIEnv *env, jclass cls, jbyteArray addrArray, jstring name, jint index)
514{
515    jint addr;
516    jbyte caddr[4];
517    struct in_addr iaddr;
518    jbyteArray ret = NULL;
519    unsigned char mac[16];
520    int len;
521    jboolean isCopy;
522    const char *name_utf;
523
524    if (name != NULL) {
525        name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
526    } else {
527        JNU_ThrowNullPointerException(env, "network interface name is NULL");
528        return NULL;
529    }
530
531    if (name_utf == NULL) {
532        if (!(*env)->ExceptionCheck(env))
533            JNU_ThrowOutOfMemoryError(env, NULL);
534        return NULL;
535    }
536
537    if (!IS_NULL(addrArray)) {
538        (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
539        addr = ((caddr[0]<<24) & 0xff000000);
540        addr |= ((caddr[1] <<16) & 0xff0000);
541        addr |= ((caddr[2] <<8) & 0xff00);
542        addr |= (caddr[3] & 0xff);
543        iaddr.s_addr = htonl(addr);
544        len = getMacAddress(env, name_utf, &iaddr, mac);
545    } else {
546        len = getMacAddress(env, name_utf, NULL, mac);
547    }
548
549    if (len > 0) {
550        ret = (*env)->NewByteArray(env, len);
551        if (!IS_NULL(ret)) {
552            (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *)(mac));
553        }
554    }
555
556    // release the UTF string and interface list
557    (*env)->ReleaseStringUTFChars(env, name, name_utf);
558
559    return ret;
560}
561
562/*
563 * Class:       java_net_NetworkInterface
564 * Method:      getMTU0
565 * Signature:   ([bLjava/lang/String;I)I
566 */
567JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0
568  (JNIEnv *env, jclass cls, jstring name, jint index)
569{
570    jboolean isCopy;
571    int sock, ret = -1;
572    const char* name_utf = NULL;
573
574    if (name != NULL) {
575        name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
576    } else {
577        JNU_ThrowNullPointerException(env, "network interface name is NULL");
578        return ret;
579    }
580
581    if (name_utf == NULL) {
582        if (!(*env)->ExceptionCheck(env))
583            JNU_ThrowOutOfMemoryError(env, NULL);
584        return ret;
585    }
586
587    if ((sock = openSocketWithFallback(env, name_utf)) < 0) {
588        (*env)->ReleaseStringUTFChars(env, name, name_utf);
589        return JNI_FALSE;
590    }
591
592    ret = getMTU(env, sock, name_utf);
593
594    (*env)->ReleaseStringUTFChars(env, name, name_utf);
595
596    close(sock);
597    return ret;
598}
599
600/*** Private methods definitions ****/
601
602static int getFlags0(JNIEnv *env, jstring name) {
603    jboolean isCopy;
604    int ret, sock, flags = 0;
605    const char *name_utf;
606
607    if (name != NULL) {
608        name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
609    } else {
610        JNU_ThrowNullPointerException(env, "network interface name is NULL");
611        return -1;
612    }
613
614    if (name_utf == NULL) {
615        if (!(*env)->ExceptionCheck(env))
616            JNU_ThrowOutOfMemoryError(env, NULL);
617        return -1;
618    }
619    if ((sock = openSocketWithFallback(env, name_utf)) < 0) {
620        (*env)->ReleaseStringUTFChars(env, name, name_utf);
621        return -1;
622    }
623
624    ret = getFlags(sock, name_utf, &flags);
625
626    close(sock);
627    (*env)->ReleaseStringUTFChars(env, name, name_utf);
628
629    if (ret < 0) {
630        JNU_ThrowByNameWithMessageAndLastError
631            (env, JNU_JAVANETPKG "SocketException", "getFlags() failed");
632        return -1;
633    }
634
635    return flags;
636}
637
638/*
639 * Creates a NetworkInterface object, populates the name, the index, and
640 * populates the InetAddress array based on the IP addresses for this
641 * interface.
642 */
643static jobject createNetworkInterface(JNIEnv *env, netif *ifs) {
644    jobject netifObj;
645    jobject name;
646    jobjectArray addrArr;
647    jobjectArray bindArr;
648    jobjectArray childArr;
649    netaddr *addrs;
650    jint addr_index, addr_count, bind_index;
651    jint child_count, child_index;
652    netaddr *addrP;
653    netif *childP;
654    jobject tmp;
655
656    // create a NetworkInterface object and populate it
657    netifObj = (*env)->NewObject(env, ni_class, ni_ctrID);
658    CHECK_NULL_RETURN(netifObj, NULL);
659    name = (*env)->NewStringUTF(env, ifs->name);
660    CHECK_NULL_RETURN(name, NULL);
661    (*env)->SetObjectField(env, netifObj, ni_nameID, name);
662    (*env)->SetObjectField(env, netifObj, ni_descID, name);
663    (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
664    (*env)->SetBooleanField(env, netifObj, ni_virutalID,
665                            ifs->virtual ? JNI_TRUE : JNI_FALSE);
666
667    // count the number of addresses on this interface
668    addr_count = 0;
669    addrP = ifs->addr;
670    while (addrP != NULL) {
671        addr_count++;
672        addrP = addrP->next;
673    }
674
675    // create the array of InetAddresses
676    addrArr = (*env)->NewObjectArray(env, addr_count, ia_class, NULL);
677    if (addrArr == NULL) {
678        return NULL;
679    }
680
681    bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL);
682    if (bindArr == NULL) {
683       return NULL;
684    }
685    addrP = ifs->addr;
686    addr_index = 0;
687    bind_index = 0;
688    while (addrP != NULL) {
689        jobject iaObj = NULL;
690        jobject ibObj = NULL;
691
692        if (addrP->family == AF_INET) {
693            iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
694            if (iaObj) {
695                setInetAddress_addr(env, iaObj, htonl(
696                    ((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr));
697            } else {
698                return NULL;
699            }
700            ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
701            if (ibObj) {
702                (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
703                if (addrP->brdcast) {
704                    jobject ia2Obj = NULL;
705                    ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
706                    if (ia2Obj) {
707                        setInetAddress_addr(env, ia2Obj, htonl(
708                            ((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr));
709                        (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj);
710                    } else {
711                        return NULL;
712                    }
713                }
714                (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
715                (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
716            } else {
717                return NULL;
718            }
719        }
720        if (addrP->family == AF_INET6) {
721            int scope=0;
722            iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
723            if (iaObj) {
724                jboolean ret = setInet6Address_ipaddress(env, iaObj,
725                    (char *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr));
726                if (ret == JNI_FALSE) {
727                    return NULL;
728                }
729
730                scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;
731
732                if (scope != 0) { /* zero is default value, no need to set */
733                    setInet6Address_scopeid(env, iaObj, scope);
734                    setInet6Address_scopeifname(env, iaObj, netifObj);
735                }
736            } else {
737                return NULL;
738            }
739            ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
740            if (ibObj) {
741                (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
742                (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
743                (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
744            } else {
745                return NULL;
746            }
747        }
748
749        (*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj);
750        addrP = addrP->next;
751    }
752
753    // see if there is any virtual interface attached to this one.
754    child_count = 0;
755    childP = ifs->childs;
756    while (childP) {
757        child_count++;
758        childP = childP->next;
759    }
760
761    childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL);
762    if (childArr == NULL) {
763        return NULL;
764    }
765
766    // create the NetworkInterface instances for the sub-interfaces as well
767    child_index = 0;
768    childP = ifs->childs;
769    while(childP) {
770        tmp = createNetworkInterface(env, childP);
771        if (tmp == NULL) {
772            return NULL;
773        }
774        (*env)->SetObjectField(env, tmp, ni_parentID, netifObj);
775        (*env)->SetObjectArrayElement(env, childArr, child_index++, tmp);
776        childP = childP->next;
777    }
778    (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
779    (*env)->SetObjectField(env, netifObj, ni_bindsID, bindArr);
780    (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
781
782    // return the NetworkInterface
783    return netifObj;
784}
785
786/*
787 * Enumerates all interfaces
788 */
789static netif *enumInterfaces(JNIEnv *env) {
790    netif *ifs = NULL;
791    int sock;
792
793    sock = openSocket(env, AF_INET);
794    if (sock < 0) {
795        return NULL;
796    }
797
798    // enumerate IPv4 addresses
799    ifs = enumIPv4Interfaces(env, sock, NULL);
800    close(sock);
801
802    // return partial list if an exception occurs in the middle of process ???
803    if (ifs == NULL && (*env)->ExceptionOccurred(env)) {
804        return NULL;
805    }
806
807    // If IPv6 is available then enumerate IPv6 addresses.
808    // User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,
809    // so we have to call ipv6_available()
810    if (ipv6_available()) {
811        sock = openSocket(env, AF_INET6);
812        if (sock < 0) {
813            freeif(ifs);
814            return NULL;
815        }
816
817        ifs = enumIPv6Interfaces(env, sock, ifs);
818        close(sock);
819
820        if ((*env)->ExceptionOccurred(env)) {
821            freeif(ifs);
822            return NULL;
823        }
824    }
825
826    return ifs;
827}
828
829/*
830 * Frees an interface list (including any attached addresses).
831 */
832static void freeif(netif *ifs) {
833    netif *currif = ifs;
834    netif *child = NULL;
835
836    while (currif != NULL) {
837        netaddr *addrP = currif->addr;
838        while (addrP != NULL) {
839            netaddr *next = addrP->next;
840            free(addrP);
841            addrP = next;
842        }
843
844        // don't forget to free the sub-interfaces
845        if (currif->childs != NULL) {
846            freeif(currif->childs);
847        }
848
849        ifs = currif->next;
850        free(currif);
851        currif = ifs;
852    }
853}
854
855static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,
856                    struct sockaddr *ifr_addrP,
857                    struct sockaddr *ifr_broadaddrP,
858                    int family, short prefix)
859{
860    netif *currif = ifs, *parent;
861    netaddr *addrP;
862    char name[IFNAMESIZE], vname[IFNAMESIZE];
863    char *name_colonP;
864    int isVirtual = 0;
865    int addr_size;
866
867    // If the interface name is a logical interface then we remove the unit
868    // number so that we have the physical interface (eg: hme0:1 -> hme0).
869    // NetworkInterface currently doesn't have any concept of physical vs.
870    // logical interfaces.
871    strncpy(name, if_name, IFNAMESIZE);
872    name[IFNAMESIZE - 1] = '\0';
873    *vname = 0;
874
875    // Create and populate the netaddr node. If allocation fails
876    // return an un-updated list.
877
878    // Allocate for addr and brdcast at once
879
880    addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in)
881                                    : sizeof(struct sockaddr_in6);
882
883    CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr) + 2 * addr_size);
884    addrP->addr = (struct sockaddr *)((char *)addrP + sizeof(netaddr));
885    memcpy(addrP->addr, ifr_addrP, addr_size);
886
887    addrP->family = family;
888    addrP->mask = prefix;
889    addrP->next = 0;
890
891    // for IPv4 add broadcast address
892    if (family == AF_INET && ifr_broadaddrP != NULL) {
893        addrP->brdcast = (struct sockaddr *)
894                             ((char *)addrP + sizeof(netaddr) + addr_size);
895        memcpy(addrP->brdcast, ifr_broadaddrP, addr_size);
896    } else {
897        addrP->brdcast = NULL;
898    }
899
900    // Deal with virtual interface with colon notation e.g. eth0:1
901    name_colonP = strchr(name, ':');
902    if (name_colonP != NULL) {
903        int flags = 0;
904        // This is a virtual interface. If we are able to access the parent
905        // we need to create a new entry if it doesn't exist yet *and* update
906        // the 'parent' interface with the new records.
907        *name_colonP = 0;
908        if (getFlags(sock, name, &flags) < 0 || flags < 0) {
909            // failed to access parent interface do not create parent.
910            // We are a virtual interface with no parent.
911            isVirtual = 1;
912            *name_colonP = ':';
913        } else {
914            // Got access to parent, so create it if necessary.
915            // Save original name to vname and truncate name by ':'
916            memcpy(vname, name, sizeof(vname));
917            vname[name_colonP - name] = ':';
918        }
919    }
920
921    // Check if this is a "new" interface. Use the interface name for
922    // matching because index isn't supported on Solaris 2.6 & 7.
923    while (currif != NULL) {
924        if (strcmp(name, currif->name) == 0) {
925            break;
926        }
927        currif = currif->next;
928    }
929
930    // If "new" then create a netif structure and insert it into the list.
931    if (currif == NULL) {
932         CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE);
933         currif->name = (char *)currif + sizeof(netif);
934         strncpy(currif->name, name, IFNAMESIZE);
935         currif->name[IFNAMESIZE - 1] = '\0';
936         currif->index = getIndex(sock, name);
937         currif->addr = NULL;
938         currif->childs = NULL;
939         currif->virtual = isVirtual;
940         currif->next = ifs;
941         ifs = currif;
942    }
943
944    // Finally insert the address on the interface
945    addrP->next = currif->addr;
946    currif->addr = addrP;
947
948    parent = currif;
949
950    // Deal with the virtual interface now.
951    if (vname[0]) {
952        netaddr *tmpaddr;
953
954        currif = parent->childs;
955
956        while (currif != NULL) {
957            if (strcmp(vname, currif->name) == 0) {
958                break;
959            }
960            currif = currif->next;
961        }
962
963        if (currif == NULL) {
964            CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE);
965            currif->name = (char *)currif + sizeof(netif);
966            strncpy(currif->name, vname, IFNAMESIZE);
967            currif->name[IFNAMESIZE - 1] = '\0';
968            currif->index = getIndex(sock, vname);
969            currif->addr = NULL; // Need to duplicate the addr entry?
970            currif->virtual = 1;
971            currif->childs = NULL;
972            currif->next = parent->childs;
973            parent->childs = currif;
974        }
975
976        CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr) + 2 * addr_size);
977        memcpy(tmpaddr, addrP, sizeof(netaddr));
978        if (addrP->addr != NULL) {
979            tmpaddr->addr = (struct sockaddr *)
980                ((char*)tmpaddr + sizeof(netaddr));
981            memcpy(tmpaddr->addr, addrP->addr, addr_size);
982        }
983
984        if (addrP->brdcast != NULL) {
985            tmpaddr->brdcast = (struct sockaddr *)
986                ((char *)tmpaddr + sizeof(netaddr) + addr_size);
987            memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size);
988        }
989
990        tmpaddr->next = currif->addr;
991        currif->addr = tmpaddr;
992    }
993
994    return ifs;
995}
996
997/*
998 * Determines the prefix value for an AF_INET subnet address.
999 */
1000static short translateIPv4AddressToPrefix(struct sockaddr_in *addr) {
1001    short prefix = 0;
1002    unsigned int mask = ntohl(addr->sin_addr.s_addr);
1003    while (mask) {
1004        mask <<= 1;
1005        prefix++;
1006    }
1007    return prefix;
1008}
1009
1010/*
1011 * Determines the prefix value for an AF_INET6 subnet address.
1012 */
1013static short translateIPv6AddressToPrefix(struct sockaddr_in6 *addr) {
1014    short prefix = 0;
1015    u_char *addrBytes = (u_char *)&(addr->sin6_addr);
1016    unsigned int byte, bit;
1017
1018    for (byte = 0; byte < sizeof(struct in6_addr); byte++, prefix += 8) {
1019        if (addrBytes[byte] != 0xff) {
1020            break;
1021        }
1022    }
1023    if (byte != sizeof(struct in6_addr)) {
1024        for (bit = 7; bit != 0; bit--, prefix++) {
1025            if (!(addrBytes[byte] & (1 << bit))) {
1026                break;
1027            }
1028        }
1029        for (; bit != 0; bit--) {
1030            if (addrBytes[byte] & (1 << bit)) {
1031                prefix = 0;
1032                break;
1033            }
1034        }
1035        if (prefix > 0) {
1036            byte++;
1037            for (; byte < sizeof(struct in6_addr); byte++) {
1038                if (addrBytes[byte]) {
1039                    prefix = 0;
1040                }
1041            }
1042        }
1043    }
1044
1045    return prefix;
1046}
1047
1048/*
1049 * Opens a socket for further ioct calls. proto is one of AF_INET or AF_INET6.
1050 */
1051static int openSocket(JNIEnv *env, int proto) {
1052    int sock;
1053
1054    if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) {
1055        // If EPROTONOSUPPORT is returned it means we don't have
1056        // support for this proto so don't throw an exception.
1057        if (errno != EPROTONOSUPPORT) {
1058            JNU_ThrowByNameWithMessageAndLastError
1059                (env, JNU_JAVANETPKG "SocketException", "Socket creation failed");
1060        }
1061        return -1;
1062    }
1063
1064    return sock;
1065}
1066
1067/** Linux **/
1068#if defined(__linux__)
1069
1070/*
1071 * Opens a socket for further ioctl calls. Tries AF_INET socket first and
1072 * if it fails return AF_INET6 socket.
1073 */
1074static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
1075    int sock;
1076
1077    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1078        if (errno == EPROTONOSUPPORT) {
1079            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1080                JNU_ThrowByNameWithMessageAndLastError
1081                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1082                return -1;
1083            }
1084        } else { // errno is not NOSUPPORT
1085            JNU_ThrowByNameWithMessageAndLastError
1086                (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1087            return -1;
1088        }
1089    }
1090
1091    // Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or
1092    // IPv6 socket regardless of type of address of an interface.
1093    return sock;
1094}
1095
1096/*
1097 * Enumerates and returns all IPv4 interfaces on Linux.
1098 */
1099static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
1100    struct ifconf ifc;
1101    struct ifreq *ifreqP;
1102    char *buf = NULL;
1103    unsigned i;
1104
1105    // do a dummy SIOCGIFCONF to determine the buffer size
1106    // SIOCGIFCOUNT doesn't work
1107    ifc.ifc_buf = NULL;
1108    if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1109        JNU_ThrowByNameWithMessageAndLastError
1110            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");
1111        return ifs;
1112    }
1113
1114    // call SIOCGIFCONF to enumerate the interfaces
1115    CHECKED_MALLOC3(buf, char *, ifc.ifc_len);
1116    ifc.ifc_buf = buf;
1117    if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1118        JNU_ThrowByNameWithMessageAndLastError
1119            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");
1120        free(buf);
1121        return ifs;
1122    }
1123
1124    // iterate through each interface
1125    ifreqP = ifc.ifc_req;
1126    for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {
1127        struct sockaddr addr, broadaddr, *broadaddrP = NULL;
1128        short prefix = 0;
1129
1130        // ignore non IPv4 addresses
1131        if (ifreqP->ifr_addr.sa_family != AF_INET) {
1132            continue;
1133        }
1134
1135        // save socket address
1136        memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));
1137
1138        // determine broadcast address, if applicable
1139        if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&
1140            ifreqP->ifr_flags & IFF_BROADCAST) {
1141
1142            // restore socket address to ifreqP
1143            memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
1144
1145            if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {
1146                memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),
1147                       sizeof(struct sockaddr));
1148                broadaddrP = &broadaddr;
1149            }
1150        }
1151
1152        // restore socket address to ifreqP
1153        memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
1154
1155        // determine netmask
1156        if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {
1157            prefix = translateIPv4AddressToPrefix(
1158                         (struct sockaddr_in *)&(ifreqP->ifr_netmask));
1159        }
1160
1161        // add interface to the list
1162        ifs = addif(env, sock, ifreqP->ifr_name, ifs,
1163                    &addr, broadaddrP, AF_INET, prefix);
1164
1165        // in case of exception, free interface list and buffer and return NULL
1166        if ((*env)->ExceptionOccurred(env)) {
1167            free(buf);
1168            freeif(ifs);
1169            return NULL;
1170        }
1171    }
1172
1173    // free buffer
1174    free(buf);
1175    return ifs;
1176}
1177
1178/*
1179 * Enumerates and returns all IPv6 interfaces on Linux.
1180 */
1181static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
1182    FILE *f;
1183    char devname[21], addr6p[8][5];
1184    int prefix, scope, dad_status, if_idx;
1185
1186    if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1187        while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
1188                      addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1189                      addr6p[4], addr6p[5], addr6p[6], addr6p[7],
1190                      &if_idx, &prefix, &scope, &dad_status, devname) != EOF) {
1191
1192            char addr6[40];
1193            struct sockaddr_in6 addr;
1194
1195            sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1196                    addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1197                    addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1198
1199            memset(&addr, 0, sizeof(struct sockaddr_in6));
1200            inet_pton(AF_INET6, addr6, (void*)addr.sin6_addr.s6_addr);
1201
1202            // set scope ID to interface index
1203            addr.sin6_scope_id = if_idx;
1204
1205            // add interface to the list
1206            ifs = addif(env, sock, devname, ifs, (struct sockaddr *)&addr,
1207                        NULL, AF_INET6, (short)prefix);
1208
1209            // if an exception occurred then return the list as is
1210            if ((*env)->ExceptionOccurred(env)) {
1211                break;
1212            }
1213       }
1214       fclose(f);
1215    }
1216    return ifs;
1217}
1218
1219/*
1220 * Try to get the interface index.
1221 */
1222static int getIndex(int sock, const char *name) {
1223    struct ifreq if2;
1224    memset((char *)&if2, 0, sizeof(if2));
1225    strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);
1226
1227    if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
1228        return -1;
1229    }
1230
1231    return if2.ifr_ifindex;
1232}
1233
1234/*
1235 * Gets the Hardware address (usually MAC address) for the named interface.
1236 * On return puts the data in buf, and returns the length, in byte, of the
1237 * MAC address. Returns -1 if there is no hardware address on that interface.
1238 */
1239static int getMacAddress
1240  (JNIEnv *env, const char *ifname, const struct in_addr *addr,
1241   unsigned char *buf)
1242{
1243    static struct ifreq ifr;
1244    int i, sock;
1245
1246    if ((sock = openSocketWithFallback(env, ifname)) < 0) {
1247        return -1;
1248    }
1249
1250    memset((char *)&ifr, 0, sizeof(ifr));
1251    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
1252    if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
1253        JNU_ThrowByNameWithMessageAndLastError
1254            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFHWADDR) failed");
1255        close(sock);
1256        return -1;
1257    }
1258
1259    close(sock);
1260    memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
1261
1262    // all bytes to 0 means no hardware address
1263    for (i = 0; i < IFHWADDRLEN; i++) {
1264        if (buf[i] != 0)
1265            return IFHWADDRLEN;
1266    }
1267
1268    return -1;
1269}
1270
1271static int getMTU(JNIEnv *env, int sock, const char *ifname) {
1272    struct ifreq if2;
1273    memset((char *)&if2, 0, sizeof(if2));
1274    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
1275
1276    if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
1277        JNU_ThrowByNameWithMessageAndLastError
1278            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");
1279        return -1;
1280    }
1281
1282    return if2.ifr_mtu;
1283}
1284
1285static int getFlags(int sock, const char *ifname, int *flags) {
1286    struct ifreq if2;
1287    memset((char *)&if2, 0, sizeof(if2));
1288    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
1289
1290    if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
1291        return -1;
1292    }
1293
1294    if (sizeof(if2.ifr_flags) == sizeof(short)) {
1295        *flags = (if2.ifr_flags & 0xffff);
1296    } else {
1297        *flags = if2.ifr_flags;
1298    }
1299    return 0;
1300}
1301
1302#endif /* __linux__ */
1303
1304/** AIX **/
1305#if defined(_AIX)
1306
1307/*
1308 * Opens a socket for further ioctl calls. Tries AF_INET socket first and
1309 * if it fails return AF_INET6 socket.
1310 */
1311static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
1312    int sock;
1313
1314    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1315        if (errno == EPROTONOSUPPORT) {
1316            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1317                JNU_ThrowByNameWithMessageAndLastError
1318                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1319                return -1;
1320            }
1321        } else { // errno is not NOSUPPORT
1322            JNU_ThrowByNameWithMessageAndLastError
1323                (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1324            return -1;
1325        }
1326    }
1327
1328    return sock;
1329}
1330
1331/*
1332 * Enumerates and returns all IPv4 interfaces on AIX.
1333 */
1334static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
1335    struct ifconf ifc;
1336    struct ifreq *ifreqP;
1337    char *buf = NULL;
1338    unsigned i;
1339
1340    // call SIOCGSIZIFCONF to get the size of SIOCGIFCONF buffer
1341    if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {
1342        JNU_ThrowByNameWithMessageAndLastError
1343            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");
1344        return ifs;
1345    }
1346
1347    // call CSIOCGIFCONF instead of SIOCGIFCONF where interface
1348    // records will always have sizeof(struct ifreq) length.
1349    // Be aware that only IPv4 data is complete this way.
1350    CHECKED_MALLOC3(buf, char *, ifc.ifc_len);
1351    ifc.ifc_buf = buf;
1352    if (ioctl(sock, CSIOCGIFCONF, (char *)&ifc) < 0) {
1353        JNU_ThrowByNameWithMessageAndLastError
1354            (env, JNU_JAVANETPKG "SocketException", "ioctl(CSIOCGIFCONF) failed");
1355        free(buf);
1356        return ifs;
1357    }
1358
1359    // iterate through each interface
1360    ifreqP = ifc.ifc_req;
1361    for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {
1362        struct sockaddr addr, broadaddr, *broadaddrP = NULL;
1363        short prefix = 0;
1364
1365        // ignore non IPv4 addresses
1366        if (ifreqP->ifr_addr.sa_family != AF_INET) {
1367            continue;
1368        }
1369
1370        // save socket address
1371        memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));
1372
1373        // determine broadcast address, if applicable
1374        if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&
1375            ifreqP->ifr_flags & IFF_BROADCAST) {
1376
1377            // restore socket address to ifreqP
1378            memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
1379
1380            if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {
1381                memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),
1382                       sizeof(struct sockaddr));
1383                broadaddrP = &broadaddr;
1384            }
1385        }
1386
1387        // restore socket address to ifreqP
1388        memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));
1389
1390        // determine netmask
1391        if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {
1392            prefix = translateIPv4AddressToPrefix(
1393                         (struct sockaddr_in *)&(ifreqP->ifr_addr));
1394        }
1395
1396        // add interface to the list
1397        ifs = addif(env, sock, ifreqP->ifr_name, ifs,
1398                    &addr, broadaddrP, AF_INET, prefix);
1399
1400        // in case of exception, free interface list and buffer and return NULL
1401        if ((*env)->ExceptionOccurred(env)) {
1402            free(buf);
1403            freeif(ifs);
1404            return NULL;
1405        }
1406    }
1407
1408    // free buffer
1409    free(buf);
1410    return ifs;
1411}
1412
1413/*
1414 * Enumerates and returns all IPv6 interfaces on AIX.
1415 */
1416static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
1417    struct ifconf ifc;
1418    struct ifreq *ifreqP;
1419    char *buf, *cp, *cplimit;
1420
1421    // call SIOCGSIZIFCONF to get size for SIOCGIFCONF buffer
1422    if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {
1423        JNU_ThrowByNameWithMessageAndLastError
1424            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");
1425        return ifs;
1426    }
1427
1428    // call SIOCGIFCONF to enumerate the interfaces
1429    CHECKED_MALLOC3(buf, char *, ifc.ifc_len);
1430    ifc.ifc_buf = buf;
1431    if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1432        JNU_ThrowByNameWithMessageAndLastError
1433            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");
1434        free(buf);
1435        return ifs;
1436    }
1437
1438    // iterate through each interface
1439    ifreqP = ifc.ifc_req;
1440    cp = (char *)ifc.ifc_req;
1441    cplimit = cp + ifc.ifc_len;
1442
1443    for (; cp < cplimit;
1444         cp += (sizeof(ifreqP->ifr_name) +
1445                MAX((ifreqP->ifr_addr).sa_len, sizeof(ifreqP->ifr_addr))))
1446    {
1447        ifreqP = (struct ifreq *)cp;
1448        short prefix = 0;
1449
1450        // ignore non IPv6 addresses
1451        if (ifreqP->ifr_addr.sa_family != AF_INET6) {
1452            continue;
1453        }
1454
1455        // determine netmask
1456        struct in6_ifreq if6;
1457        memset((char *)&if6, 0, sizeof(if6));
1458        strncpy(if6.ifr_name, ifreqP->ifr_name, sizeof(if6.ifr_name) - 1);
1459        memcpy(&(if6.ifr_Addr), &(ifreqP->ifr_addr),
1460               sizeof(struct sockaddr_in6));
1461        if (ioctl(sock, SIOCGIFNETMASK6, (char *)&if6) >= 0) {
1462            prefix = translateIPv6AddressToPrefix(&(if6.ifr_Addr));
1463        }
1464
1465        // set scope ID to interface index
1466        ((struct sockaddr_in6 *)&(ifreqP->ifr_addr))->sin6_scope_id =
1467            getIndex(sock, ifreqP->ifr_name);
1468
1469        // add interface to the list
1470        ifs = addif(env, sock, ifreqP->ifr_name, ifs,
1471                    (struct sockaddr *)&(ifreqP->ifr_addr),
1472                    NULL, AF_INET6, prefix);
1473
1474        // if an exception occurred then free the list
1475        if ((*env)->ExceptionOccurred(env)) {
1476            free(buf);
1477            freeif(ifs);
1478            return NULL;
1479        }
1480    }
1481
1482    // free buffer
1483    free(buf);
1484    return ifs;
1485}
1486
1487/*
1488 * Try to get the interface index.
1489 */
1490static int getIndex(int sock, const char *name) {
1491    int index = if_nametoindex(name);
1492    return (index == 0) ? -1 : index;
1493}
1494
1495/*
1496 * Gets the Hardware address (usually MAC address) for the named interface.
1497 * On return puts the data in buf, and returns the length, in byte, of the
1498 * MAC address. Returns -1 if there is no hardware address on that interface.
1499 */
1500static int getMacAddress
1501  (JNIEnv *env, const char *ifname, const struct in_addr *addr,
1502   unsigned char *buf)
1503{
1504    int size;
1505    struct kinfo_ndd *nddp;
1506    void *end;
1507
1508    size = getkerninfo(KINFO_NDD, 0, 0, 0);
1509    if (size == 0) {
1510        return -1;
1511    }
1512
1513    if (size < 0) {
1514        perror("getkerninfo 1");
1515        return -1;
1516    }
1517
1518    nddp = (struct kinfo_ndd *)malloc(size);
1519
1520    if (!nddp) {
1521        JNU_ThrowOutOfMemoryError(env,
1522            "Network interface getMacAddress native buffer allocation failed");
1523        return -1;
1524    }
1525
1526    if (getkerninfo(KINFO_NDD, nddp, &size, 0) < 0) {
1527        perror("getkerninfo 2");
1528        return -1;
1529    }
1530
1531    end = (void *)nddp + size;
1532    while ((void *)nddp < end) {
1533        if (!strcmp(nddp->ndd_alias, ifname) ||
1534                !strcmp(nddp->ndd_name, ifname)) {
1535            bcopy(nddp->ndd_addr, buf, 6);
1536            return 6;
1537        } else {
1538            nddp++;
1539        }
1540    }
1541
1542    return -1;
1543}
1544
1545static int getMTU(JNIEnv *env, int sock, const char *ifname) {
1546    struct ifreq if2;
1547    memset((char *)&if2, 0, sizeof(if2));
1548    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
1549
1550    if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
1551        JNU_ThrowByNameWithMessageAndLastError
1552            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");
1553        return -1;
1554    }
1555
1556    return if2.ifr_mtu;
1557}
1558
1559static int getFlags(int sock, const char *ifname, int *flags) {
1560    struct ifreq if2;
1561    memset((char *)&if2, 0, sizeof(if2));
1562    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
1563
1564    if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
1565        return -1;
1566    }
1567
1568    if (sizeof(if2.ifr_flags) == sizeof(short)) {
1569        *flags = (if2.ifr_flags & 0xffff);
1570    } else {
1571        *flags = if2.ifr_flags;
1572    }
1573    return 0;
1574}
1575
1576#endif /* _AIX */
1577
1578/** Solaris **/
1579#if defined(__solaris__)
1580
1581/*
1582 * Opens a socket for further ioctl calls. Tries AF_INET socket first and
1583 * if it fails return AF_INET6 socket.
1584 */
1585static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
1586    int sock, alreadyV6 = 0;
1587    struct lifreq if2;
1588
1589    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1590        if (errno == EPROTONOSUPPORT) {
1591            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1592                JNU_ThrowByNameWithMessageAndLastError
1593                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1594                return -1;
1595            }
1596            alreadyV6 = 1;
1597        } else { // errno is not NOSUPPORT
1598            JNU_ThrowByNameWithMessageAndLastError
1599                (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1600            return -1;
1601        }
1602    }
1603
1604    // Solaris requires that we have an IPv6 socket to query an  interface
1605    // without an IPv4 address - check it here. POSIX 1 require the kernel to
1606    // return ENOTTY if the call is inappropriate for a device e.g. the NETMASK
1607    // for a device having IPv6 only address but not all devices follow the
1608    // standard so fall back on any error. It's not an ecologically friendly
1609    // gesture but more reliable.
1610    if (!alreadyV6) {
1611        memset((char *)&if2, 0, sizeof(if2));
1612        strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
1613        if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
1614            close(sock);
1615            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1616                JNU_ThrowByNameWithMessageAndLastError
1617                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1618                return -1;
1619            }
1620        }
1621    }
1622
1623    return sock;
1624}
1625
1626/*
1627 * Enumerates and returns all IPv4 interfaces on Solaris.
1628 */
1629static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
1630    struct lifconf ifc;
1631    struct lifreq *ifreqP;
1632    struct lifnum numifs;
1633    char *buf = NULL;
1634    unsigned i;
1635
1636    // call SIOCGLIFNUM to get the interface count
1637    numifs.lifn_family = AF_INET;
1638    numifs.lifn_flags = 0;
1639    if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {
1640        JNU_ThrowByNameWithMessageAndLastError
1641            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFNUM) failed");
1642        return ifs;
1643    }
1644
1645    // call SIOCGLIFCONF to enumerate the interfaces
1646    ifc.lifc_len = numifs.lifn_count * sizeof(struct lifreq);
1647    CHECKED_MALLOC3(buf, char *, ifc.lifc_len);
1648    ifc.lifc_buf = buf;
1649    ifc.lifc_family = AF_INET;
1650    ifc.lifc_flags = 0;
1651    if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {
1652        JNU_ThrowByNameWithMessageAndLastError
1653            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFCONF) failed");
1654        free(buf);
1655        return ifs;
1656    }
1657
1658    // iterate through each interface
1659    ifreqP = ifc.lifc_req;
1660    for (i = 0; i < numifs.lifn_count; i++, ifreqP++) {
1661        struct sockaddr addr, *broadaddrP = NULL;
1662
1663        // ignore non IPv4 addresses
1664        if (ifreqP->lifr_addr.ss_family != AF_INET) {
1665            continue;
1666        }
1667
1668        // save socket address
1669        memcpy(&addr, &(ifreqP->lifr_addr), sizeof(struct sockaddr));
1670
1671        // determine broadcast address, if applicable
1672        if ((ioctl(sock, SIOCGLIFFLAGS, ifreqP) == 0) &&
1673            ifreqP->lifr_flags & IFF_BROADCAST) {
1674
1675            // restore socket address to ifreqP
1676            memcpy(&(ifreqP->lifr_addr), &addr, sizeof(struct sockaddr));
1677
1678            // query broadcast address and set pointer to it
1679            if (ioctl(sock, SIOCGLIFBRDADDR, ifreqP) == 0) {
1680                broadaddrP = (struct sockaddr *)&(ifreqP->lifr_broadaddr);
1681            }
1682        }
1683
1684        // add to the list
1685        ifs = addif(env, sock, ifreqP->lifr_name, ifs,
1686                    &addr, broadaddrP, AF_INET, (short)ifreqP->lifr_addrlen);
1687
1688        // if an exception occurred we return immediately
1689        if ((*env)->ExceptionOccurred(env)) {
1690            free(buf);
1691            return ifs;
1692        }
1693   }
1694
1695    // free buffer
1696    free(buf);
1697    return ifs;
1698}
1699
1700/*
1701 * Enumerates and returns all IPv6 interfaces on Solaris.
1702 */
1703static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
1704    struct lifconf ifc;
1705    struct lifreq *ifreqP;
1706    struct lifnum numifs;
1707    char *buf = NULL;
1708    unsigned i;
1709
1710    // call SIOCGLIFNUM to get the interface count
1711    numifs.lifn_family = AF_INET6;
1712    numifs.lifn_flags = 0;
1713    if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {
1714        JNU_ThrowByNameWithMessageAndLastError
1715            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFNUM) failed");
1716        return ifs;
1717    }
1718
1719    // call SIOCGLIFCONF to enumerate the interfaces
1720    ifc.lifc_len = numifs.lifn_count * sizeof(struct lifreq);
1721    CHECKED_MALLOC3(buf, char *, ifc.lifc_len);
1722    ifc.lifc_buf = buf;
1723    ifc.lifc_family = AF_INET6;
1724    ifc.lifc_flags = 0;
1725    if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {
1726        JNU_ThrowByNameWithMessageAndLastError
1727            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFCONF) failed");
1728        free(buf);
1729        return ifs;
1730    }
1731
1732    // iterate through each interface
1733    ifreqP = ifc.lifc_req;
1734    for (i = 0; i < numifs.lifn_count; i++, ifreqP++) {
1735
1736        // ignore non IPv6 addresses
1737        if (ifreqP->lifr_addr.ss_family != AF_INET6) {
1738            continue;
1739        }
1740
1741        // set scope ID to interface index
1742        ((struct sockaddr_in6 *)&(ifreqP->lifr_addr))->sin6_scope_id =
1743            getIndex(sock, ifreqP->lifr_name);
1744
1745        // add to the list
1746        ifs = addif(env, sock, ifreqP->lifr_name, ifs,
1747                    (struct sockaddr *)&(ifreqP->lifr_addr),
1748                    NULL, AF_INET6, (short)ifreqP->lifr_addrlen);
1749
1750        // if an exception occurred we return immediately
1751        if ((*env)->ExceptionOccurred(env)) {
1752            free(buf);
1753            return ifs;
1754        }
1755    }
1756
1757    // free buffer
1758    free(buf);
1759    return ifs;
1760}
1761
1762/*
1763 * Try to get the interface index.
1764 * (Not supported on Solaris 2.6 or 7)
1765 */
1766static int getIndex(int sock, const char *name) {
1767    struct lifreq if2;
1768    memset((char *)&if2, 0, sizeof(if2));
1769    strncpy(if2.lifr_name, name, sizeof(if2.lifr_name) - 1);
1770
1771    if (ioctl(sock, SIOCGLIFINDEX, (char *)&if2) < 0) {
1772        return -1;
1773    }
1774
1775    return if2.lifr_index;
1776}
1777
1778/*
1779 * Solaris specific DLPI code to get hardware address from a device.
1780 * Unfortunately, at least up to Solaris X, you have to have special
1781 * privileges (i.e. be root).
1782 */
1783static int getMacFromDevice
1784  (JNIEnv *env, const char *ifname, unsigned char *retbuf)
1785{
1786    char style1dev[MAXPATHLEN];
1787    int fd;
1788    dl_phys_addr_req_t dlpareq;
1789    dl_phys_addr_ack_t *dlpaack;
1790    struct strbuf msg;
1791    char buf[128];
1792    int flags = 0;
1793
1794    // Device is in /dev.  e.g.: /dev/bge0
1795    strcpy(style1dev, DEV_PREFIX);
1796    strcat(style1dev, ifname);
1797    if ((fd = open(style1dev, O_RDWR)) < 0) {
1798        // Can't open it. We probably are missing the privilege.
1799        // We'll have to try something else
1800        return 0;
1801    }
1802
1803    dlpareq.dl_primitive = DL_PHYS_ADDR_REQ;
1804    dlpareq.dl_addr_type = DL_CURR_PHYS_ADDR;
1805
1806    msg.buf = (char *)&dlpareq;
1807    msg.len = DL_PHYS_ADDR_REQ_SIZE;
1808
1809    if (putmsg(fd, &msg, NULL, 0) < 0) {
1810        JNU_ThrowByNameWithMessageAndLastError
1811            (env, JNU_JAVANETPKG "SocketException", "putmsg() failed");
1812        return -1;
1813    }
1814
1815    dlpaack = (dl_phys_addr_ack_t *)buf;
1816
1817    msg.buf = (char *)buf;
1818    msg.len = 0;
1819    msg.maxlen = sizeof (buf);
1820    if (getmsg(fd, &msg, NULL, &flags) < 0) {
1821        JNU_ThrowByNameWithMessageAndLastError
1822            (env, JNU_JAVANETPKG "SocketException", "getmsg() failed");
1823        return -1;
1824    }
1825
1826    if (msg.len < DL_PHYS_ADDR_ACK_SIZE || dlpaack->dl_primitive != DL_PHYS_ADDR_ACK) {
1827        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1828                        "Couldn't obtain phys addr\n");
1829        return -1;
1830    }
1831
1832    memcpy(retbuf, &buf[dlpaack->dl_addr_offset], dlpaack->dl_addr_length);
1833    return dlpaack->dl_addr_length;
1834}
1835
1836/*
1837 * Gets the Hardware address (usually MAC address) for the named interface.
1838 * On return puts the data in buf, and returns the length, in byte, of the
1839 * MAC address. Returns -1 if there is no hardware address on that interface.
1840 */
1841static int getMacAddress
1842  (JNIEnv *env, const char *ifname, const struct in_addr *addr,
1843   unsigned char *buf)
1844{
1845    struct lifreq if2;
1846    int len, i, sock;
1847
1848    if ((sock = openSocketWithFallback(env, ifname)) < 0) {
1849        return -1;
1850    }
1851
1852    // First, try the new (S11) SIOCGLIFHWADDR ioctl(). If that fails
1853    // try the old way.
1854    memset((char *)&if2, 0, sizeof(if2));
1855    strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
1856
1857    if (ioctl(sock, SIOCGLIFHWADDR, &if2) != -1) {
1858        struct sockaddr_dl *sp;
1859        sp = (struct sockaddr_dl *)&if2.lifr_addr;
1860        memcpy(buf, &sp->sdl_data[0], sp->sdl_alen);
1861        close(sock);
1862        return sp->sdl_alen;
1863    }
1864
1865    // On Solaris we have to use DLPI, but it will only work if we have
1866    // privileged access (i.e. root). If that fails, we try a lookup
1867    // in the ARP table, which requires an IPv4 address.
1868    if (((len = getMacFromDevice(env, ifname, buf)) == 0) && (addr != NULL)) {
1869        struct arpreq arpreq;
1870        struct sockaddr_in *sin;
1871        struct sockaddr_in ipAddr;
1872
1873        len = 6; //???
1874
1875        sin = (struct sockaddr_in *)&arpreq.arp_pa;
1876        memset((char *)&arpreq, 0, sizeof(struct arpreq));
1877        ipAddr.sin_port = 0;
1878        ipAddr.sin_family = AF_INET;
1879        memcpy(&ipAddr.sin_addr, addr, sizeof(struct in_addr));
1880        memcpy(&arpreq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
1881        arpreq.arp_flags= ATF_PUBL;
1882
1883        if (ioctl(sock, SIOCGARP, &arpreq) < 0) {
1884            close(sock);
1885            return -1;
1886        }
1887
1888        memcpy(buf, &arpreq.arp_ha.sa_data[0], len);
1889    }
1890    close(sock);
1891
1892    // all bytes to 0 means no hardware address
1893    for (i = 0; i < len; i++) {
1894        if (buf[i] != 0)
1895            return len;
1896    }
1897
1898    return -1;
1899}
1900
1901static int getMTU(JNIEnv *env, int sock, const char *ifname) {
1902    struct lifreq if2;
1903    memset((char *)&if2, 0, sizeof(if2));
1904    strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
1905
1906    if (ioctl(sock, SIOCGLIFMTU, (char *)&if2) < 0) {
1907        JNU_ThrowByNameWithMessageAndLastError
1908            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFMTU) failed");
1909        return -1;
1910    }
1911
1912    return if2.lifr_mtu;
1913}
1914
1915static int getFlags(int sock, const char *ifname, int *flags) {
1916    struct lifreq if2;
1917    memset((char *)&if2, 0, sizeof(if2));
1918    strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
1919
1920    if (ioctl(sock, SIOCGLIFFLAGS, (char *)&if2) < 0) {
1921        return -1;
1922    }
1923
1924    *flags = if2.lifr_flags;
1925    return 0;
1926}
1927
1928#endif /* __solaris__ */
1929
1930/** BSD **/
1931#if defined(_ALLBSD_SOURCE)
1932
1933/*
1934 * Opens a socket for further ioctl calls. Tries AF_INET socket first and
1935 * if it fails return AF_INET6 socket.
1936 */
1937static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
1938    int sock;
1939
1940    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1941        if (errno == EPROTONOSUPPORT) {
1942            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1943                JNU_ThrowByNameWithMessageAndLastError
1944                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1945                return -1;
1946            }
1947        } else { // errno is not NOSUPPORT
1948            JNU_ThrowByNameWithMessageAndLastError
1949                (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1950            return -1;
1951        }
1952    }
1953
1954    return sock;
1955}
1956
1957/*
1958 * Enumerates and returns all IPv4 interfaces on BSD.
1959 */
1960static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
1961    struct ifaddrs *ifa, *origifa;
1962
1963    if (getifaddrs(&origifa) != 0) {
1964        JNU_ThrowByNameWithMessageAndLastError
1965            (env, JNU_JAVANETPKG "SocketException", "getifaddrs() failed");
1966        return ifs;
1967    }
1968
1969    for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
1970        struct sockaddr *broadaddrP = NULL;
1971
1972        // ignore non IPv4 addresses
1973        if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)
1974            continue;
1975
1976        // set ifa_broadaddr, if there is one
1977        if ((ifa->ifa_flags & IFF_POINTOPOINT) == 0 &&
1978            ifa->ifa_flags & IFF_BROADCAST) {
1979            broadaddrP = ifa->ifa_dstaddr;
1980        }
1981
1982        // add interface to the list
1983        ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr,
1984                    broadaddrP, AF_INET,
1985                    translateIPv4AddressToPrefix((struct sockaddr_in *)
1986                                                 ifa->ifa_netmask));
1987
1988        // if an exception occurred then free the list
1989        if ((*env)->ExceptionOccurred(env)) {
1990            freeifaddrs(origifa);
1991            freeif(ifs);
1992            return NULL;
1993        }
1994    }
1995
1996    // free ifaddrs buffer
1997    freeifaddrs(origifa);
1998    return ifs;
1999}
2000
2001/*
2002 * Enumerates and returns all IPv6 interfaces on BSD.
2003 */
2004static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
2005    struct ifaddrs *ifa, *origifa;
2006
2007    if (getifaddrs(&origifa) != 0) {
2008        JNU_ThrowByNameWithMessageAndLastError
2009            (env, JNU_JAVANETPKG "SocketException", "getifaddrs() failed");
2010        return ifs;
2011    }
2012
2013    for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
2014        // ignore non IPv6 addresses
2015        if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET6)
2016            continue;
2017
2018        // set scope ID to interface index
2019        ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id =
2020            getIndex(sock, ifa->ifa_name);
2021
2022        // add interface to the list
2023        ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, NULL,
2024                    AF_INET6,
2025                    translateIPv6AddressToPrefix((struct sockaddr_in6 *)
2026                                                 ifa->ifa_netmask));
2027
2028        // if an exception occurred then free the list
2029        if ((*env)->ExceptionOccurred(env)) {
2030            freeifaddrs(origifa);
2031            freeif(ifs);
2032            return NULL;
2033        }
2034    }
2035
2036    // free ifaddrs buffer
2037    freeifaddrs(origifa);
2038    return ifs;
2039}
2040
2041/*
2042 * Try to get the interface index.
2043 */
2044static int getIndex(int sock, const char *name) {
2045#if !defined(__FreeBSD__)
2046    int index = if_nametoindex(name);
2047    return (index == 0) ? -1 : index;
2048#else
2049    struct ifreq if2;
2050    memset((char *)&if2, 0, sizeof(if2));
2051    strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);
2052
2053    if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
2054        return -1;
2055    }
2056
2057    return if2.ifr_index;
2058#endif
2059}
2060
2061/*
2062 * Gets the Hardware address (usually MAC address) for the named interface.
2063 * On return puts the data in buf, and returns the length, in byte, of the
2064 * MAC address. Returns -1 if there is no hardware address on that interface.
2065 */
2066static int getMacAddress
2067  (JNIEnv *env, const char *ifname, const struct in_addr *addr,
2068   unsigned char *buf)
2069{
2070    struct ifaddrs *ifa0, *ifa;
2071    struct sockaddr *saddr;
2072    int i;
2073
2074    // grab the interface list
2075    if (!getifaddrs(&ifa0)) {
2076        // cycle through the interfaces
2077        for (i = 0, ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next, i++) {
2078            saddr = ifa->ifa_addr;
2079            // link layer contains the MAC address
2080            if (saddr->sa_family == AF_LINK && !strcmp(ifname, ifa->ifa_name)) {
2081                struct sockaddr_dl *sadl = (struct sockaddr_dl *) saddr;
2082                // check the address has the correct length
2083                if (sadl->sdl_alen == ETHER_ADDR_LEN) {
2084                    memcpy(buf, (sadl->sdl_data + sadl->sdl_nlen), ETHER_ADDR_LEN);
2085                    freeifaddrs(ifa0);
2086                    return ETHER_ADDR_LEN;
2087                }
2088            }
2089        }
2090        freeifaddrs(ifa0);
2091    }
2092
2093    return -1;
2094}
2095
2096static int getMTU(JNIEnv *env, int sock, const char *ifname) {
2097    struct ifreq if2;
2098    memset((char *)&if2, 0, sizeof(if2));
2099    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
2100
2101    if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
2102        JNU_ThrowByNameWithMessageAndLastError
2103            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");
2104        return -1;
2105    }
2106
2107    return if2.ifr_mtu;
2108}
2109
2110static int getFlags(int sock, const char *ifname, int *flags) {
2111    struct ifreq if2;
2112    memset((char *)&if2, 0, sizeof(if2));
2113    strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);
2114
2115    if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
2116        return -1;
2117    }
2118
2119    if (sizeof(if2.ifr_flags) == sizeof(short)) {
2120        *flags = (if2.ifr_flags & 0xffff);
2121    } else {
2122        *flags = if2.ifr_flags;
2123    }
2124    return 0;
2125}
2126#endif /* _ALLBSD_SOURCE */
2127