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