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