1 /*
   2  * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 #include <errno.h>
  28 #include <strings.h>
  29 #include <netinet/in.h>
  30 #include <stdlib.h>
  31 #include <string.h>
  32 #include <sys/types.h>
  33 #include <sys/socket.h>
  34 #include <arpa/inet.h>
  35 #include <net/if.h>
  36 #include <net/if_arp.h>
  37 
  38 #ifdef __solaris__
  39 #include <sys/dlpi.h>
  40 #include <fcntl.h>
  41 #include <stropts.h>
  42 #include <sys/sockio.h>
  43 #endif
  44 
  45 #ifdef __linux__
  46 #include <sys/ioctl.h>
  47 #include <bits/ioctls.h>
  48 #include <sys/utsname.h>
  49 #include <stdio.h>
  50 #endif
  51 
  52 #ifdef __linux__
  53 #define _PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
  54 #endif
  55 
  56 #include "jvm.h"
  57 #include "jni_util.h"
  58 #include "net_util.h"
  59 
  60 typedef struct _netaddr  {
  61     struct sockaddr *addr;
  62     struct sockaddr *brdcast;
  63     short mask;
  64     int family; /* to make searches simple */
  65     struct _netaddr *next;
  66 } netaddr;
  67 
  68 typedef struct _netif {
  69     char *name;
  70     int index;
  71     char virtual;
  72     netaddr *addr;
  73     struct _netif *childs;
  74     struct _netif *next;
  75 } netif;
  76 
  77 /************************************************************************
  78  * NetworkInterface
  79  */
  80 
  81 #include "java_net_NetworkInterface.h"
  82 
  83 /************************************************************************
  84  * NetworkInterface
  85  */
  86 jclass ni_class;
  87 jfieldID ni_nameID;
  88 jfieldID ni_indexID;
  89 jfieldID ni_descID;
  90 jfieldID ni_addrsID;
  91 jfieldID ni_bindsID;
  92 jfieldID ni_virutalID;
  93 jfieldID ni_childsID;
  94 jfieldID ni_parentID;
  95 jmethodID ni_ctrID;
  96 
  97 static jclass ni_iacls;
  98 static jclass ni_ia4cls;
  99 static jclass ni_ia6cls;
 100 static jclass ni_ibcls;
 101 static jmethodID ni_ia4ctrID;
 102 static jmethodID ni_ia6ctrID;
 103 static jmethodID ni_ibctrID;
 104 static jfieldID ni_iaaddressID;
 105 static jfieldID ni_iafamilyID;
 106 static jfieldID ni_ia6ipaddressID;
 107 static jfieldID ni_ibaddressID;
 108 static jfieldID ni_ib4broadcastID;
 109 static jfieldID ni_ib4maskID;
 110 
 111 /** Private methods declarations **/
 112 static jobject createNetworkInterface(JNIEnv *env, netif *ifs);
 113 static int     getFlags0(JNIEnv *env, jstring  ifname);
 114 
 115 static netif  *enumInterfaces(JNIEnv *env);
 116 static netif  *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs);
 117 
 118 #ifdef AF_INET6
 119 static netif  *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs);
 120 #endif
 121 
 122 static netif  *addif(JNIEnv *env, int sock, const char * if_name, netif *ifs, struct sockaddr* ifr_addrP, int family, short prefix);
 123 static void    freeif(netif *ifs);
 124 
 125 static int     openSocket(JNIEnv *env, int proto);
 126 static int     openSocketWithFallback(JNIEnv *env, const char *ifname);
 127 
 128 
 129 static struct  sockaddr *getBroadcast(JNIEnv *env, int sock, const char *name, struct sockaddr *brdcast_store);
 130 static short   getSubnet(JNIEnv *env, int sock, const char *ifname);
 131 static int     getIndex(int sock, const char *ifname);
 132 
 133 static int     getFlags(int sock, const char *ifname);
 134 static int     getMacAddress(JNIEnv *env, int sock,  const char* ifname, const struct in_addr* addr, unsigned char *buf);
 135 static int     getMTU(JNIEnv *env, int sock, const char *ifname);
 136 
 137 
 138 
 139 #ifdef __solaris__
 140 static netif *enumIPvXInterfaces(JNIEnv *env, int sock, netif *ifs, int family);
 141 static int    getMacFromDevice(JNIEnv *env, const char* ifname, unsigned char* retbuf);
 142 #endif
 143 
 144 
 145 /******************* Java entry points *****************************/
 146 
 147 /*
 148  * Class:     java_net_NetworkInterface
 149  * Method:    init
 150  * Signature: ()V
 151  */
 152 JNIEXPORT void JNICALL
 153 Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls) {
 154     ni_class = (*env)->FindClass(env,"java/net/NetworkInterface");
 155     ni_class = (*env)->NewGlobalRef(env, ni_class);
 156     ni_nameID = (*env)->GetFieldID(env, ni_class,"name", "Ljava/lang/String;");
 157     ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
 158     ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;");
 159     ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;");
 160     ni_descID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;");
 161     ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z");
 162     ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;");
 163     ni_parentID = (*env)->GetFieldID(env, ni_class, "parent", "Ljava/net/NetworkInterface;");
 164     ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
 165 
 166     ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
 167     ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
 168     ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
 169     ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
 170     ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address");
 171     ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls);
 172     ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
 173     ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
 174     ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
 175     ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V");
 176     ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
 177     ni_iaaddressID = (*env)->GetFieldID(env, ni_iacls, "address", "I");
 178     ni_iafamilyID = (*env)->GetFieldID(env, ni_iacls, "family", "I");
 179     ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B");
 180     ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;");
 181     ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;");
 182     ni_ib4maskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
 183 }
 184 
 185 
 186 /*
 187  * Class:     java_net_NetworkInterface
 188  * Method:    getByName0
 189  * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
 190  */
 191 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0
 192     (JNIEnv *env, jclass cls, jstring name) {
 193 
 194     netif *ifs, *curr;
 195     jboolean isCopy;
 196     const char* name_utf;
 197     jobject obj = NULL;
 198 
 199     ifs = enumInterfaces(env);
 200     if (ifs == NULL) {
 201         return NULL;
 202     }
 203 
 204     name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
 205 
 206     /*
 207      * Search the list of interface based on name
 208      */
 209     curr = ifs;
 210     while (curr != NULL) {
 211         if (strcmp(name_utf, curr->name) == 0) {
 212             break;
 213         }
 214         curr = curr->next;
 215     }
 216 
 217     /* if found create a NetworkInterface */
 218     if (curr != NULL) {;
 219         obj = createNetworkInterface(env, curr);
 220     }
 221 
 222     /* release the UTF string and interface list */
 223     (*env)->ReleaseStringUTFChars(env, name, name_utf);
 224     freeif(ifs);
 225 
 226     return obj;
 227 }
 228 
 229 
 230 /*
 231  * Class:     java_net_NetworkInterface
 232  * Method:    getByIndex0
 233  * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
 234  */
 235 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0
 236     (JNIEnv *env, jclass cls, jint index) {
 237 
 238     netif *ifs, *curr;
 239     jobject obj = NULL;
 240 
 241     if (index <= 0) {
 242         return NULL;
 243     }
 244 
 245     ifs = enumInterfaces(env);
 246     if (ifs == NULL) {
 247         return NULL;
 248     }
 249 
 250     /*
 251      * Search the list of interface based on index
 252      */
 253     curr = ifs;
 254     while (curr != NULL) {
 255         if (index == curr->index) {
 256             break;
 257         }
 258         curr = curr->next;
 259     }
 260 
 261     /* if found create a NetworkInterface */
 262     if (curr != NULL) {;
 263         obj = createNetworkInterface(env, curr);
 264     }
 265 
 266     freeif(ifs);
 267     return obj;
 268 }
 269 
 270 /*
 271  * Class:     java_net_NetworkInterface
 272  * Method:    getByInetAddress0
 273  * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
 274  */
 275 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
 276     (JNIEnv *env, jclass cls, jobject iaObj) {
 277 
 278     netif *ifs, *curr;
 279 
 280 #ifdef AF_INET6
 281     int family = (  (*env)->GetIntField(env, iaObj, ni_iafamilyID) == IPv4 ) ? AF_INET : AF_INET6;
 282 #else
 283     int family =  AF_INET;
 284 #endif
 285 
 286     jobject obj = NULL;
 287     jboolean match = JNI_FALSE;
 288 
 289     ifs = enumInterfaces(env);
 290     if (ifs == NULL) {
 291         return NULL;
 292     }
 293 
 294     curr = ifs;
 295     while (curr != NULL) {
 296         netaddr *addrP = curr->addr;
 297 
 298         /*
 299          * Iterate through each address on the interface
 300          */
 301         while (addrP != NULL) {
 302 
 303             if (family == addrP->family) {
 304                 if (family == AF_INET) {
 305                     int address1 = htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr);
 306                     int address2 = (*env)->GetIntField(env, iaObj, ni_iaaddressID);
 307 
 308                     if (address1 == address2) {
 309                         match = JNI_TRUE;
 310                         break;
 311                     }
 312                 }
 313 
 314 #ifdef AF_INET6
 315                 if (family == AF_INET6) {
 316                     jbyte *bytes = (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr);
 317                     jbyteArray ipaddress = (*env)->GetObjectField(env, iaObj, ni_ia6ipaddressID);
 318                     jbyte caddr[16];
 319                     int i;
 320 
 321                     (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddr);
 322                     i = 0;
 323                     while (i < 16) {
 324                         if (caddr[i] != bytes[i]) {
 325                             break;
 326                         }
 327                         i++;
 328                     }
 329                     if (i >= 16) {
 330                         match = JNI_TRUE;
 331                         break;
 332                     }
 333                 }
 334 #endif
 335 
 336             }
 337 
 338             if (match) {
 339                 break;
 340             }
 341             addrP = addrP->next;
 342         }
 343 
 344         if (match) {
 345             break;
 346         }
 347         curr = curr->next;
 348     }
 349 
 350     /* if found create a NetworkInterface */
 351     if (match) {;
 352         obj = createNetworkInterface(env, curr);
 353     }
 354 
 355     freeif(ifs);
 356     return obj;
 357 }
 358 
 359 
 360 /*
 361  * Class:     java_net_NetworkInterface
 362  * Method:    getAll
 363  * Signature: ()[Ljava/net/NetworkInterface;
 364  */
 365 JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll
 366     (JNIEnv *env, jclass cls) {
 367 
 368     netif *ifs, *curr;
 369     jobjectArray netIFArr;
 370     jint arr_index, ifCount;
 371 
 372     ifs = enumInterfaces(env);
 373     if (ifs == NULL) {
 374         return NULL;
 375     }
 376 
 377     /* count the interface */
 378     ifCount = 0;
 379     curr = ifs;
 380     while (curr != NULL) {
 381         ifCount++;
 382         curr = curr->next;
 383     }
 384 
 385     /* allocate a NetworkInterface array */
 386     netIFArr = (*env)->NewObjectArray(env, ifCount, cls, NULL);
 387     if (netIFArr == NULL) {
 388         freeif(ifs);
 389         return NULL;
 390     }
 391 
 392     /*
 393      * Iterate through the interfaces, create a NetworkInterface instance
 394      * for each array element and populate the object.
 395      */
 396     curr = ifs;
 397     arr_index = 0;
 398     while (curr != NULL) {
 399         jobject netifObj;
 400 
 401         netifObj = createNetworkInterface(env, curr);
 402         if (netifObj == NULL) {
 403             freeif(ifs);
 404             return NULL;
 405         }
 406 
 407         /* put the NetworkInterface into the array */
 408         (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
 409 
 410         curr = curr->next;
 411     }
 412 
 413     freeif(ifs);
 414     return netIFArr;
 415 }
 416 
 417 
 418 /*
 419  * Class:     java_net_NetworkInterface
 420  * Method:    isUp0
 421  * Signature: (Ljava/lang/String;I)Z
 422  */
 423 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0(JNIEnv *env, jclass cls, jstring name, jint index) {
 424     int ret = getFlags0(env, name);
 425     return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE :  JNI_FALSE;
 426 }
 427 
 428 /*
 429  * Class:     java_net_NetworkInterface
 430  * Method:    isP2P0
 431  * Signature: (Ljava/lang/String;I)Z
 432  */
 433 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0(JNIEnv *env, jclass cls, jstring name, jint index) {
 434     int ret = getFlags0(env, name);
 435     return (ret & IFF_POINTOPOINT) ? JNI_TRUE :  JNI_FALSE;
 436 }
 437 
 438 /*
 439  * Class:     java_net_NetworkInterface
 440  * Method:    isLoopback0
 441  * Signature: (Ljava/lang/String;I)Z
 442  */
 443 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0(JNIEnv *env, jclass cls, jstring name, jint index) {
 444     int ret = getFlags0(env, name);
 445     return (ret & IFF_LOOPBACK) ? JNI_TRUE :  JNI_FALSE;
 446 }
 447 
 448 /*
 449  * Class:     java_net_NetworkInterface
 450  * Method:    supportsMulticast0
 451  * Signature: (Ljava/lang/String;I)Z
 452  */
 453 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0(JNIEnv *env, jclass cls, jstring name, jint index) {
 454     int ret = getFlags0(env, name);
 455     return (ret & IFF_MULTICAST) ? JNI_TRUE :  JNI_FALSE;
 456 }
 457 
 458 /*
 459  * Class:     java_net_NetworkInterface
 460  * Method:    getMacAddr0
 461  * Signature: ([bLjava/lang/String;I)[b
 462  */
 463 JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0(JNIEnv *env, jclass class, jbyteArray addrArray, jstring name, jint index) {
 464     jint addr;
 465     jbyte caddr[4];
 466     struct in_addr iaddr;
 467     jbyteArray ret = NULL;
 468     unsigned char mac[16];
 469     int len;
 470     int sock;
 471     jboolean isCopy;
 472     const char* name_utf;
 473 
 474     name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
 475 
 476     if ((sock =openSocketWithFallback(env, name_utf)) < 0) {
 477        (*env)->ReleaseStringUTFChars(env, name, name_utf);
 478        return JNI_FALSE;
 479     }
 480 
 481 
 482     if (!IS_NULL(addrArray)) {
 483        (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
 484        addr = ((caddr[0]<<24) & 0xff000000);
 485        addr |= ((caddr[1] <<16) & 0xff0000);
 486        addr |= ((caddr[2] <<8) & 0xff00);
 487        addr |= (caddr[3] & 0xff);
 488        iaddr.s_addr = htonl(addr);
 489        len = getMacAddress(env, sock, name_utf, &iaddr, mac);
 490     } else {
 491        len = getMacAddress(env, sock, name_utf,NULL, mac);
 492     }
 493     if (len > 0) {
 494        ret = (*env)->NewByteArray(env, len);
 495        if (IS_NULL(ret)) {
 496           /* we may have memory to free at the end of this */
 497           goto fexit;
 498        }
 499        (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) (mac));
 500     }
 501  fexit:
 502    /* release the UTF string and interface list */
 503    (*env)->ReleaseStringUTFChars(env, name, name_utf);
 504 
 505    close(sock);
 506    return ret;
 507 }
 508 
 509 /*
 510  * Class:       java_net_NetworkInterface
 511  * Method:      getMTU0
 512  * Signature:   ([bLjava/lang/String;I)I
 513  */
 514 
 515 JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0(JNIEnv *env, jclass class, jstring name, jint index) {
 516     jboolean isCopy;
 517     int ret = -1;
 518     int sock;
 519     const char* name_utf;
 520 
 521     name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
 522 
 523     if ((sock =openSocketWithFallback(env, name_utf)) < 0) {
 524        (*env)->ReleaseStringUTFChars(env, name, name_utf);
 525        return JNI_FALSE;
 526     }
 527 
 528     ret = getMTU(env, sock, name_utf);
 529 
 530     (*env)->ReleaseStringUTFChars(env, name, name_utf);
 531 
 532     close(sock);
 533     return ret;
 534 }
 535 
 536 /*** Private methods definitions ****/
 537 
 538 static int getFlags0(JNIEnv *env, jstring name) {
 539     jboolean isCopy;
 540     int ret, sock;
 541     const char* name_utf;
 542 
 543     name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
 544 
 545     if ((sock = openSocketWithFallback(env, name_utf)) < 0) {
 546         (*env)->ReleaseStringUTFChars(env, name, name_utf);
 547          return -1;
 548     }
 549 
 550     name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
 551 
 552     ret = getFlags(sock, name_utf);
 553 
 554     close(sock);
 555     (*env)->ReleaseStringUTFChars(env, name, name_utf);
 556 
 557     if (ret < 0) {
 558         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL  SIOCGLIFFLAGS failed");
 559         return -1;
 560     }
 561 
 562     return ret;
 563 }
 564 
 565 
 566 
 567 
 568 /*
 569  * Create a NetworkInterface object, populate the name and index, and
 570  * populate the InetAddress array based on the IP addresses for this
 571  * interface.
 572  */
 573 jobject createNetworkInterface(JNIEnv *env, netif *ifs) {
 574     jobject netifObj;
 575     jobject name;
 576     jobjectArray addrArr;
 577     jobjectArray bindArr;
 578     jobjectArray childArr;
 579     netaddr *addrs;
 580     jint addr_index, addr_count, bind_index;
 581     jint child_count, child_index;
 582     netaddr *addrP;
 583     netif *childP;
 584     jobject tmp;
 585 
 586     /*
 587      * Create a NetworkInterface object and populate it
 588      */
 589     netifObj = (*env)->NewObject(env, ni_class, ni_ctrID);
 590     name = (*env)->NewStringUTF(env, ifs->name);
 591     if (netifObj == NULL || name == NULL) {
 592         return NULL;
 593     }
 594     (*env)->SetObjectField(env, netifObj, ni_nameID, name);
 595     (*env)->SetObjectField(env, netifObj, ni_descID, name);
 596     (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
 597     (*env)->SetBooleanField(env, netifObj, ni_virutalID, ifs->virtual ? JNI_TRUE : JNI_FALSE);
 598 
 599     /*
 600      * Count the number of address on this interface
 601      */
 602     addr_count = 0;
 603     addrP = ifs->addr;
 604     while (addrP != NULL) {
 605         addr_count++;
 606         addrP = addrP->next;
 607     }
 608 
 609     /*
 610      * Create the array of InetAddresses
 611      */
 612     addrArr = (*env)->NewObjectArray(env, addr_count,  ni_iacls, NULL);
 613     if (addrArr == NULL) {
 614         return NULL;
 615     }
 616 
 617     bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL);
 618     if (bindArr == NULL) {
 619        return NULL;
 620     }
 621     addrP = ifs->addr;
 622     addr_index = 0;
 623     bind_index = 0;
 624     while (addrP != NULL) {
 625         jobject iaObj = NULL;
 626         jobject ibObj = NULL;
 627 
 628         if (addrP->family == AF_INET) {
 629             iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
 630             if (iaObj) {
 631                  (*env)->SetIntField(env, iaObj, ni_iaaddressID, htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr));
 632             }
 633             ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
 634             if (ibObj) {
 635                  (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
 636                  if (addrP->brdcast) {
 637                     jobject ia2Obj = NULL;
 638                     ia2Obj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
 639                     if (ia2Obj) {
 640                        (*env)->SetIntField(env, ia2Obj, ni_iaaddressID,
 641                                                                htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr));
 642                        (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj);
 643                        (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
 644                     }
 645                  }
 646                  (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
 647             }
 648         }
 649 
 650 #ifdef AF_INET6
 651         if (addrP->family == AF_INET6) {
 652             int scope=0;
 653             iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
 654             if (iaObj) {
 655                 jbyteArray ipaddress = (*env)->NewByteArray(env, 16);
 656                 if (ipaddress == NULL) {
 657                     return NULL;
 658                 }
 659                 (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
 660                                                                         (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr));
 661 
 662                 scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;
 663 
 664                 if (scope != 0) { /* zero is default value, no need to set */
 665                     (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
 666                     (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
 667                     (*env)->SetObjectField(env, iaObj, ia6_scopeifnameID, netifObj);
 668                 }
 669                 (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress);
 670             }
 671             ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
 672             if (ibObj) {
 673                 (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
 674                 (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
 675                 (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
 676             }
 677         }
 678 #endif
 679 
 680         if (iaObj == NULL) {
 681             return NULL;
 682         }
 683 
 684         (*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj);
 685         addrP = addrP->next;
 686     }
 687 
 688     /*
 689      * See if there is any virtual interface attached to this one.
 690      */
 691     child_count = 0;
 692     childP = ifs->childs;
 693     while (childP) {
 694         child_count++;
 695         childP = childP->next;
 696     }
 697 
 698     childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL);
 699     if (childArr == NULL) {
 700         return NULL;
 701     }
 702 
 703     /*
 704      * Create the NetworkInterface instances for the sub-interfaces as
 705      * well.
 706      */
 707     child_index = 0;
 708     childP = ifs->childs;
 709     while(childP) {
 710       tmp = createNetworkInterface(env, childP);
 711       if (tmp == NULL) {
 712          return NULL;
 713       }
 714       (*env)->SetObjectField(env, tmp, ni_parentID, netifObj);
 715       (*env)->SetObjectArrayElement(env, childArr, child_index++, tmp);
 716       childP = childP->next;
 717     }
 718     (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
 719     (*env)->SetObjectField(env, netifObj, ni_bindsID, bindArr);
 720     (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
 721 
 722     /* return the NetworkInterface */
 723     return netifObj;
 724 }
 725 
 726 /*
 727  * Enumerates all interfaces
 728  */
 729 static netif *enumInterfaces(JNIEnv *env) {
 730     netif *ifs;
 731     int sock;
 732 
 733     /*
 734      * Enumerate IPv4 addresses
 735      */
 736 
 737     sock = openSocket(env, AF_INET);
 738     if (sock < 0 && (*env)->ExceptionOccurred(env)) {
 739         return NULL;
 740     }
 741 
 742     ifs = enumIPv4Interfaces(env, sock, NULL);
 743     close(sock);
 744 
 745     if (ifs == NULL && (*env)->ExceptionOccurred(env)) {
 746         return NULL;
 747     }
 748 
 749     /* return partial list if exception occure in the middle of process ???*/
 750 
 751     /*
 752      * If IPv6 is available then enumerate IPv6 addresses.
 753      */
 754 #ifdef AF_INET6
 755 
 756         /* User can disable ipv6 expicitly by -Djava.net.preferIPv4Stack=true,
 757          * so we have to call ipv6_available()
 758          */
 759         if (ipv6_available()) {
 760 
 761            sock =  openSocket(env, AF_INET6);
 762            if (sock < 0 && (*env)->ExceptionOccurred(env)) {
 763                freeif(ifs);
 764                return NULL;
 765            }
 766 
 767            ifs = enumIPv6Interfaces(env, sock, ifs);
 768            close(sock);
 769 
 770            if ((*env)->ExceptionOccurred(env)) {
 771               freeif(ifs);
 772               return NULL;
 773            }
 774 
 775        }
 776 #endif
 777 
 778     return ifs;
 779 }
 780 
 781 #define CHECKED_MALLOC3(_pointer,_type,_size) \
 782        do{ \
 783         _pointer = (_type)malloc( _size ); \
 784         if (_pointer == NULL) { \
 785             JNU_ThrowOutOfMemoryError(env, "heap allocation failed"); \
 786             return ifs; /* return untouched list */ \
 787         } \
 788        } while(0)
 789 
 790 
 791 /*
 792  * Free an interface list (including any attached addresses)
 793  */
 794 void freeif(netif *ifs) {
 795     netif *currif = ifs;
 796     netif *child = NULL;
 797 
 798     while (currif != NULL) {
 799         netaddr *addrP = currif->addr;
 800         while (addrP != NULL) {
 801             netaddr *next = addrP->next;
 802             free(addrP);
 803             addrP = next;
 804          }
 805 
 806             /*
 807             * Don't forget to free the sub-interfaces.
 808             */
 809           if (currif->childs != NULL) {
 810                 freeif(currif->childs);
 811           }
 812 
 813           ifs = currif->next;
 814           free(currif);
 815           currif = ifs;
 816     }
 817 }
 818 
 819 netif *addif(JNIEnv *env, int sock, const char * if_name, netif *ifs, struct sockaddr* ifr_addrP, int family, short prefix) {
 820     netif *currif = ifs, *parent;
 821     netaddr *addrP;
 822 
 823     #ifdef __solaris__
 824     char name[LIFNAMSIZ],  vname[LIFNAMSIZ];
 825     #else
 826     char name[IFNAMSIZ],  vname[IFNAMSIZ];
 827     #endif
 828 
 829     char  *name_colonP;
 830     int mask;
 831     int isVirtual = 0;
 832     int addr_size;
 833 
 834     /*
 835      * If the interface name is a logical interface then we
 836      * remove the unit number so that we have the physical
 837      * interface (eg: hme0:1 -> hme0). NetworkInterface
 838      * currently doesn't have any concept of physical vs.
 839      * logical interfaces.
 840      */
 841     strcpy(name, if_name);
 842     *vname = 0;
 843 
 844     /*
 845      * Create and populate the netaddr node. If allocation fails
 846      * return an un-updated list.
 847      */
 848     /*Allocate for addr and brdcast at once*/
 849 
 850 #ifdef AF_INET6
 851     addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
 852 #else
 853     addr_size = sizeof(struct sockaddr_in);
 854 #endif
 855 
 856     CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr)+2*addr_size);
 857     addrP->addr = (struct sockaddr *)( (char *) addrP+sizeof(netaddr) );
 858     memcpy(addrP->addr, ifr_addrP, addr_size);
 859 
 860     addrP->family = family;
 861     addrP->brdcast = NULL;
 862     addrP->mask = prefix;
 863     addrP->next = 0;
 864     if (family == AF_INET) {
 865       /*
 866        * Deal with brodcast addr & subnet mask
 867        */
 868        struct sockaddr * brdcast_to = (struct sockaddr *) ((char *) addrP + sizeof(netaddr) + addr_size);
 869        addrP->brdcast = getBroadcast(env, sock, name,  brdcast_to );
 870 
 871        if (addrP->brdcast && (mask = getSubnet(env, sock, name)) != -1) {
 872            addrP->mask = mask;
 873        }
 874      }
 875 
 876     /**
 877      * Deal with virtual interface with colon notaion e.g. eth0:1
 878      */
 879     name_colonP = strchr(name, ':');
 880     if (name_colonP != NULL) {
 881       /**
 882        * This is a virtual interface. If we are able to access the parent
 883        * we need to create a new entry if it doesn't exist yet *and* update
 884        * the 'parent' interface with the new records.
 885        */
 886         *name_colonP = 0;
 887         if (getFlags(sock, name) < 0) {
 888             // failed to access parent interface do not create parent.
 889             // We are a virtual interface with no parent.
 890             isVirtual = 1;
 891             *name_colonP = ':';
 892         }
 893         else{
 894            // Got access to parent, so create it if necessary.
 895            // Save original name to vname and truncate name by ':'
 896             memcpy(vname, name, sizeof(vname) );
 897             vname[name_colonP - name] = ':';
 898         }
 899     }
 900 
 901     /*
 902      * Check if this is a "new" interface. Use the interface
 903      * name for matching because index isn't supported on
 904      * Solaris 2.6 & 7.
 905      */
 906     while (currif != NULL) {
 907         if (strcmp(name, currif->name) == 0) {
 908             break;
 909         }
 910         currif = currif->next;
 911     }
 912 
 913     /*
 914      * If "new" then create an netif structure and
 915      * insert it onto the list.
 916      */
 917     if (currif == NULL) {
 918          CHECKED_MALLOC3(currif, netif *, sizeof(netif)+IFNAMSIZ );
 919          currif->name = (char *) currif+sizeof(netif);
 920          strcpy(currif->name, name);
 921          currif->index = getIndex(sock, name);
 922          currif->addr = NULL;
 923          currif->childs = NULL;
 924          currif->virtual = isVirtual;
 925          currif->next = ifs;
 926          ifs = currif;
 927     }
 928 
 929     /*
 930      * Finally insert the address on the interface
 931      */
 932     addrP->next = currif->addr;
 933     currif->addr = addrP;
 934 
 935     parent = currif;
 936 
 937     /**
 938      * Let's deal with the virtual interface now.
 939      */
 940     if (vname[0]) {
 941         netaddr *tmpaddr;
 942 
 943         currif = parent->childs;
 944 
 945         while (currif != NULL) {
 946             if (strcmp(vname, currif->name) == 0) {
 947                 break;
 948             }
 949             currif = currif->next;
 950         }
 951 
 952         if (currif == NULL) {
 953             CHECKED_MALLOC3(currif, netif *, sizeof(netif)+ IFNAMSIZ );
 954             currif->name = (char *) currif + sizeof(netif);
 955             strcpy(currif->name, vname);
 956             currif->index = getIndex(sock, vname);
 957             currif->addr = NULL;
 958            /* Need to duplicate the addr entry? */
 959             currif->virtual = 1;
 960             currif->childs = NULL;
 961             currif->next = parent->childs;
 962             parent->childs = currif;
 963         }
 964 
 965         CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr)+2*addr_size);
 966         memcpy(tmpaddr, addrP, sizeof(netaddr));
 967         if (addrP->addr != NULL) {
 968             tmpaddr->addr = (struct sockaddr *) ( (char*)tmpaddr + sizeof(netaddr) ) ;
 969             memcpy(tmpaddr->addr, addrP->addr, addr_size);
 970         }
 971 
 972         if (addrP->brdcast != NULL) {
 973             tmpaddr->brdcast = (struct sockaddr *) ((char *) tmpaddr + sizeof(netaddr)+addr_size);
 974             memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size);
 975         }
 976 
 977         tmpaddr->next = currif->addr;
 978         currif->addr = tmpaddr;
 979     }
 980 
 981     return ifs;
 982 }
 983 
 984 /* Open socket for further ioct calls
 985  * proto is AF_INET/AF_INET6
 986  */
 987 static int  openSocket(JNIEnv *env, int proto){
 988     int sock;
 989 
 990     if ((sock = JVM_Socket(proto, SOCK_DGRAM, 0)) < 0) {
 991         /*
 992          * If EPROTONOSUPPORT is returned it means we don't have
 993          * support  for this proto so don't throw an exception.
 994          */
 995         if (errno != EPROTONOSUPPORT) {
 996             NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "Socket creation failed");
 997         }
 998         return -1;
 999     }
1000 
1001     return sock;
1002 }
1003 
1004 
1005 /** Linux **/
1006 #ifdef __linux__
1007 /* Open socket for further ioct calls, try v4 socket first and
1008  * if it falls return v6 socket
1009  */
1010 
1011 #ifdef AF_INET6
1012 static int openSocketWithFallback(JNIEnv *env, const char *ifname){
1013     int sock;
1014     struct ifreq if2;
1015 
1016      if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1017          if (errno == EPROTONOSUPPORT){
1018               if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
1019                  NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1020                  return -1;
1021               }
1022          }
1023          else{ // errno is not NOSUPPORT
1024              NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1025              return -1;
1026          }
1027    }
1028 
1029      /* Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or IPv6 socket regardless of type
1030         of address of an interface */
1031 
1032        return sock;
1033 }
1034 
1035 #else
1036 static int openSocketWithFallback(JNIEnv *env, const char *ifname){
1037     return openSocket(env,AF_INET);
1038 }
1039 #endif
1040 
1041 static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
1042     struct ifconf ifc;
1043     struct ifreq *ifreqP;
1044     char *buf;
1045     int numifs;
1046     unsigned i;
1047 
1048 
1049     /* need to do a dummy SIOCGIFCONF to determine the buffer size.
1050      * SIOCGIFCOUNT doesn't work
1051      */
1052     ifc.ifc_buf = NULL;
1053     if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1054         NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGIFCONF failed");
1055         return ifs;
1056     }
1057 
1058     CHECKED_MALLOC3(buf,char *, ifc.ifc_len);
1059 
1060     ifc.ifc_buf = buf;
1061     if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
1062         NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGIFCONF failed");
1063         (void) free(buf);
1064         return ifs;
1065     }
1066 
1067     /*
1068      * Iterate through each interface
1069      */
1070     ifreqP = ifc.ifc_req;
1071     for (i=0; i<ifc.ifc_len/sizeof (struct ifreq); i++, ifreqP++) {
1072         /*
1073          * Add to the list
1074          */
1075         ifs = addif(env, sock, ifreqP->ifr_name, ifs, (struct sockaddr *) & (ifreqP->ifr_addr), AF_INET, 0);
1076 
1077         /*
1078          * If an exception occurred then free the list
1079          */
1080         if ((*env)->ExceptionOccurred(env)) {
1081             free(buf);
1082             freeif(ifs);
1083             return NULL;
1084         }
1085     }
1086 
1087     /*
1088      * Free socket and buffer
1089      */
1090     free(buf);
1091     return ifs;
1092 }
1093 
1094 
1095 /*
1096  * Enumerates and returns all IPv6 interfaces on Linux
1097  */
1098 
1099 #ifdef AF_INET6
1100 static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
1101     FILE *f;
1102     char addr6[40], devname[21];
1103     char addr6p[8][5];
1104     int plen, scope, dad_status, if_idx;
1105     uint8_t ipv6addr[16];
1106 
1107     if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1108         while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1109                          addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7],
1110                          &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
1111 
1112             struct netif *ifs_ptr = NULL;
1113             struct netif *last_ptr = NULL;
1114             struct sockaddr_in6 addr;
1115 
1116             sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1117                            addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1118             inet_pton(AF_INET6, addr6, ipv6addr);
1119 
1120             memset(&addr, 0, sizeof(struct sockaddr_in6));
1121             memcpy((void*)addr.sin6_addr.s6_addr, (const void*)ipv6addr, 16);
1122 
1123             addr.sin6_scope_id = if_idx;
1124 
1125             ifs = addif(env, sock, devname, ifs, (struct sockaddr *)&addr, AF_INET6, plen);
1126 
1127 
1128             /*
1129              * If an exception occurred then return the list as is.
1130              */
1131             if ((*env)->ExceptionOccurred(env)) {
1132                 fclose(f);
1133                 return ifs;
1134             }
1135        }
1136        fclose(f);
1137     }
1138     return ifs;
1139 }
1140 #endif
1141 
1142 
1143 static int getIndex(int sock, const char *name){
1144      /*
1145       * Try to get the interface index
1146       * (Not supported on Solaris 2.6 or 7)
1147       */
1148     struct ifreq if2;
1149     strcpy(if2.ifr_name, name);
1150 
1151     if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
1152         return -1;
1153     }
1154 
1155     return if2.ifr_ifindex;
1156 }
1157 
1158 /**
1159  * Returns the IPv4 broadcast address of a named interface, if it exists.
1160  * Returns 0 if it doesn't have one.
1161  */
1162 static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) {
1163   struct sockaddr *ret = NULL;
1164   struct ifreq if2;
1165 
1166   memset((char *) &if2, 0, sizeof(if2));
1167   strcpy(if2.ifr_name, ifname);
1168 
1169   /* Let's make sure the interface does have a broadcast address */
1170   if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2)  < 0) {
1171       NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL  SIOCGIFFLAGS failed");
1172       return ret;
1173   }
1174 
1175   if (if2.ifr_flags & IFF_BROADCAST) {
1176       /* It does, let's retrieve it*/
1177       if (ioctl(sock, SIOCGIFBRDADDR, (char *)&if2) < 0) {
1178           NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFBRDADDR failed");
1179           return ret;
1180       }
1181 
1182       ret = brdcast_store;
1183       memcpy(ret, &if2.ifr_broadaddr, sizeof(struct sockaddr));
1184   }
1185 
1186   return ret;
1187 }
1188 
1189 /**
1190  * Returns the IPv4 subnet prefix length (aka subnet mask) for the named
1191  * interface, if it has one, otherwise return -1.
1192  */
1193 static short getSubnet(JNIEnv *env, int sock, const char *ifname) {
1194     unsigned int mask;
1195     short ret;
1196     struct ifreq if2;
1197 
1198     memset((char *) &if2, 0, sizeof(if2));
1199     strcpy(if2.ifr_name, ifname);
1200 
1201     if (ioctl(sock, SIOCGIFNETMASK, (char *)&if2) < 0) {
1202         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFNETMASK failed");
1203         return -1;
1204     }
1205 
1206     mask = ntohl(((struct sockaddr_in*)&(if2.ifr_addr))->sin_addr.s_addr);
1207     ret = 0;
1208     while (mask) {
1209        mask <<= 1;
1210        ret++;
1211     }
1212 
1213     return ret;
1214 }
1215 
1216 /**
1217  * Get the Hardware address (usually MAC address) for the named interface.
1218  * return puts the data in buf, and returns the length, in byte, of the
1219  * MAC address. Returns -1 if there is no hardware address on that interface.
1220  */
1221 static int getMacAddress(JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr, unsigned char *buf) {
1222     static struct ifreq ifr;
1223     int i;
1224 
1225     strcpy(ifr.ifr_name, ifname);
1226     if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
1227         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFHWADDR failed");
1228         return -1;
1229     }
1230 
1231     memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
1232 
1233    /*
1234     * All bytes to 0 means no hardware address.
1235     */
1236 
1237     for (i = 0; i < IFHWADDRLEN; i++) {
1238         if (buf[i] != 0)
1239             return IFHWADDRLEN;
1240     }
1241 
1242     return -1;
1243 }
1244 
1245 static int getMTU(JNIEnv *env, int sock,  const char *ifname) {
1246     struct ifreq if2;
1247 
1248     memset((char *) &if2, 0, sizeof(if2));
1249     strcpy(if2.ifr_name, ifname);
1250 
1251     if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
1252         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFMTU failed");
1253         return -1;
1254     }
1255 
1256     return  if2.ifr_mtu;
1257 }
1258 
1259 static int getFlags(int sock, const char *ifname) {
1260   struct ifreq if2;
1261   int ret = -1;
1262 
1263   memset((char *) &if2, 0, sizeof(if2));
1264   strcpy(if2.ifr_name, ifname);
1265 
1266   if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0){
1267       return -1;
1268   }
1269 
1270   return if2.ifr_flags;
1271 }
1272 
1273 #endif
1274 
1275 /** Solaris **/
1276 #ifdef __solaris__
1277 /* Open socket for further ioct calls, try v4 socket first and
1278  * if it falls return v6 socket
1279  */
1280 
1281 #ifdef AF_INET6
1282 static int openSocketWithFallback(JNIEnv *env, const char *ifname){
1283     int sock, alreadyV6 = 0;
1284     struct lifreq if2;
1285 
1286      if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1287          if (errno == EPROTONOSUPPORT){
1288               if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
1289                  NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1290                  return -1;
1291               }
1292 
1293               alreadyV6=1;
1294          }
1295          else{ // errno is not NOSUPPORT
1296              NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1297              return -1;
1298          }
1299    }
1300 
1301      /**
1302       * Solaris requires that we have IPv6 socket to query an
1303       * interface without IPv4 address - check it here
1304       * POSIX 1 require the kernell to return ENOTTY if the call is
1305       * unappropriate for device e.g. NETMASK for device having IPv6
1306       * only address but not all devices follows the standart so
1307       * fallback on any error.  It's not an ecology friendly but more
1308       * reliable.
1309       */
1310 
1311     if (! alreadyV6 ){
1312         memset((char *) &if2, 0, sizeof(if2));
1313         strcpy(if2.lifr_name, ifname);
1314         if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
1315                 close(sock);
1316                 if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
1317                       NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1318                       return -1;
1319                 }
1320         }
1321     }
1322 
1323     return sock;
1324 }
1325 
1326 #else
1327 static int openSocketWithFallback(JNIEnv *env, const char *ifname){
1328     return openSocket(env,AF_INET);
1329 }
1330 #endif
1331 
1332 /*
1333  * Enumerates and returns all IPv4 interfaces
1334  * (linux verison)
1335  */
1336 
1337 static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
1338      return enumIPvXInterfaces(env,sock, ifs, AF_INET);
1339 }
1340 
1341 #ifdef AF_INET6
1342 static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
1343     return enumIPvXInterfaces(env,sock, ifs, AF_INET6);
1344 }
1345 #endif
1346 
1347 /*
1348    Enumerates and returns all interfaces on Solaris
1349    use the same code for IPv4 and IPv6
1350  */
1351 static netif *enumIPvXInterfaces(JNIEnv *env, int sock, netif *ifs, int family) {
1352     struct lifconf ifc;
1353     struct lifreq *ifr;
1354     int n;
1355     char *buf;
1356     struct lifnum numifs;
1357     unsigned bufsize;
1358 
1359     /*
1360      * Get the interface count
1361      */
1362     numifs.lifn_family = family;
1363     numifs.lifn_flags = 0;
1364     if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {
1365         NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGLIFNUM failed");
1366         return ifs;
1367     }
1368 
1369     /*
1370      *  Enumerate the interface configurations
1371      */
1372     bufsize = numifs.lifn_count * sizeof (struct lifreq);
1373     CHECKED_MALLOC3(buf, char *, bufsize);
1374 
1375     ifc.lifc_family = family;
1376     ifc.lifc_flags = 0;
1377     ifc.lifc_len = bufsize;
1378     ifc.lifc_buf = buf;
1379     if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {
1380         NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGLIFCONF failed");
1381         free(buf);
1382         return ifs;
1383     }
1384 
1385     /*
1386      * Iterate through each interface
1387      */
1388     ifr = ifc.lifc_req;
1389     for (n=0; n<numifs.lifn_count; n++, ifr++) {
1390         int index = -1;
1391         struct lifreq if2;
1392 
1393         /*
1394         * Ignore either IPv4 or IPv6 addresses
1395         */
1396         if (ifr->lifr_addr.ss_family != family) {
1397             continue;
1398         }
1399 
1400 #ifdef AF_INET6
1401         if (ifr->lifr_addr.ss_family == AF_INET6) {
1402             struct sockaddr_in6 *s6= (struct sockaddr_in6 *)&(ifr->lifr_addr);
1403             s6->sin6_scope_id = getIndex(sock, ifr->lifr_name);
1404         }
1405 #endif
1406 
1407         /* add to the list */
1408         ifs = addif(env, sock,ifr->lifr_name, ifs, (struct sockaddr *)&(ifr->lifr_addr),family, (short) ifr->lifr_addrlen);
1409 
1410         /*
1411         * If an exception occurred we return immediately
1412         */
1413         if ((*env)->ExceptionOccurred(env)) {
1414             free(buf);
1415             return ifs;
1416         }
1417 
1418    }
1419 
1420     free(buf);
1421     return ifs;
1422 }
1423 
1424 static int getIndex(int sock, const char *name){
1425    /*
1426     * Try to get the interface index
1427     * (Not supported on Solaris 2.6 or 7)
1428     */
1429     struct lifreq if2;
1430     strcpy(if2.lifr_name, name);
1431 
1432     if (ioctl(sock, SIOCGLIFINDEX, (char *)&if2) < 0) {
1433         return -1;
1434     }
1435 
1436     return if2.lifr_index;
1437 }
1438 
1439 /**
1440  * Returns the IPv4 broadcast address of a named interface, if it exists.
1441  * Returns 0 if it doesn't have one.
1442  */
1443 static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) {
1444     struct sockaddr *ret = NULL;
1445     struct lifreq if2;
1446 
1447     memset((char *) &if2, 0, sizeof(if2));
1448     strcpy(if2.lifr_name, ifname);
1449 
1450     /* Let's make sure the interface does have a broadcast address */
1451     if (ioctl(sock, SIOCGLIFFLAGS, (char *)&if2)  < 0) {
1452         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL  SIOCGLIFFLAGS failed");
1453         return ret;
1454     }
1455 
1456     if (if2.lifr_flags & IFF_BROADCAST) {
1457         /* It does, let's retrieve it*/
1458         if (ioctl(sock, SIOCGLIFBRDADDR, (char *)&if2) < 0) {
1459             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFBRDADDR failed");
1460             return ret;
1461         }
1462 
1463         ret = brdcast_store;
1464         memcpy(ret, &if2.lifr_broadaddr, sizeof(struct sockaddr));
1465     }
1466 
1467     return ret;
1468 }
1469 
1470 /**
1471  * Returns the IPv4 subnet prefix length (aka subnet mask) for the named
1472  * interface, if it has one, otherwise return -1.
1473  */
1474 static short getSubnet(JNIEnv *env, int sock, const char *ifname) {
1475     unsigned int mask;
1476     short ret;
1477     struct lifreq if2;
1478 
1479     memset((char *) &if2, 0, sizeof(if2));
1480     strcpy(if2.lifr_name, ifname);
1481 
1482     if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
1483         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFNETMASK failed");
1484         return -1;
1485     }
1486 
1487     mask = ntohl(((struct sockaddr_in*)&(if2.lifr_addr))->sin_addr.s_addr);
1488     ret = 0;
1489 
1490     while (mask) {
1491        mask <<= 1;
1492        ret++;
1493     }
1494 
1495     return ret;
1496 }
1497 
1498 
1499 
1500 #define DEV_PREFIX  "/dev/"
1501 
1502 /**
1503  * Solaris specific DLPI code to get hardware address from a device.
1504  * Unfortunately, at least up to Solaris X, you have to have special
1505  * privileges (i.e. be root).
1506  */
1507 static int getMacFromDevice(JNIEnv *env, const char* ifname, unsigned char* retbuf) {
1508     char style1dev[MAXPATHLEN];
1509     int fd;
1510     dl_phys_addr_req_t dlpareq;
1511     dl_phys_addr_ack_t *dlpaack;
1512     struct strbuf msg;
1513     char buf[128];
1514     int flags = 0;
1515 
1516    /**
1517     * Device is in /dev
1518     * e.g.: /dev/bge0
1519     */
1520     strcpy(style1dev, DEV_PREFIX);
1521     strcat(style1dev, ifname);
1522     if ((fd = open(style1dev, O_RDWR)) < 0) {
1523         /*
1524          * Can't open it. We probably are missing the privilege.
1525          * We'll have to try something else
1526          */
1527          return 0;
1528     }
1529 
1530     dlpareq.dl_primitive = DL_PHYS_ADDR_REQ;
1531     dlpareq.dl_addr_type = DL_CURR_PHYS_ADDR;
1532 
1533     msg.buf = (char *)&dlpareq;
1534     msg.len = DL_PHYS_ADDR_REQ_SIZE;
1535 
1536     if (putmsg(fd, &msg, NULL, 0) < 0) {
1537         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "putmsg failed");
1538         return -1;
1539     }
1540 
1541     dlpaack = (dl_phys_addr_ack_t *)buf;
1542 
1543     msg.buf = (char *)buf;
1544     msg.len = 0;
1545     msg.maxlen = sizeof (buf);
1546     if (getmsg(fd, &msg, NULL, &flags) < 0) {
1547         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "getmsg failed");
1548         return -1;
1549     }
1550 
1551     if (msg.len < DL_PHYS_ADDR_ACK_SIZE || dlpaack->dl_primitive != DL_PHYS_ADDR_ACK) {
1552         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Couldn't obtain phys addr\n");
1553         return -1;
1554     }
1555 
1556     memcpy(retbuf, &buf[dlpaack->dl_addr_offset], dlpaack->dl_addr_length);
1557     return dlpaack->dl_addr_length;
1558 }
1559 
1560 /**
1561  * Get the Hardware address (usually MAC address) for the named interface.
1562  * return puts the data in buf, and returns the length, in byte, of the
1563  * MAC address. Returns -1 if there is no hardware address on that interface.
1564  */
1565 static int getMacAddress(JNIEnv *env, int sock, const char *ifname,  const struct in_addr* addr, unsigned char *buf) {
1566     struct arpreq arpreq;
1567     struct sockaddr_in* sin;
1568     struct sockaddr_in ipAddr;
1569     int len, i;
1570 
1571    /**
1572     * On Solaris we have to use DLPI, but it will only work if we have
1573     * privileged access (i.e. root). If that fails, we try a lookup
1574     * in the ARP table, which requires an IPv4 address.
1575     */
1576     if ((len = getMacFromDevice(env, ifname, buf))  == 0) {
1577         /*DLPI failed - trying to do arp lookup*/
1578 
1579        if (addr == NULL) {
1580           /**
1581            * No IPv4 address for that interface, so can't do an ARP lookup.
1582            */
1583            return -1;
1584       }
1585 
1586       len = 6; //???
1587 
1588       sin = (struct sockaddr_in *) &arpreq.arp_pa;
1589       memset((char *) &arpreq, 0, sizeof(struct arpreq));
1590       ipAddr.sin_port = 0;
1591       ipAddr.sin_family = AF_INET;
1592       memcpy(&ipAddr.sin_addr, addr, sizeof(struct in_addr));
1593       memcpy(&arpreq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
1594       arpreq.arp_flags= ATF_PUBL;
1595 
1596       if (ioctl(sock, SIOCGARP, &arpreq) < 0) {
1597           if (errno != ENXIO) {
1598               // "No such device or address" means no hardware address, so it's
1599               // normal don't throw an exception
1600               NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL failed");
1601               return -1;
1602           }
1603      }
1604 
1605      memcpy(buf, &arpreq.arp_ha.sa_data[0], len );
1606   }
1607 
1608     /*
1609      * All bytes to 0 means no hardware address.
1610      */
1611 
1612     for (i = 0; i < len; i++) {
1613       if (buf[i] != 0)
1614          return len;
1615     }
1616 
1617     return -1;
1618 }
1619 
1620 static int getMTU(JNIEnv *env, int sock,  const char *ifname) {
1621     struct lifreq if2;
1622 
1623     memset((char *) &if2, 0, sizeof(if2));
1624     strcpy(if2.lifr_name, ifname);
1625 
1626     if (ioctl(sock, SIOCGLIFMTU, (char *)&if2) < 0) {
1627         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFMTU failed");
1628         return -1;
1629     }
1630 
1631     return  if2.lifr_mtu;
1632 }
1633 
1634 
1635 static int getFlags(int sock, const char *ifname) {
1636      struct   lifreq lifr;
1637      memset((caddr_t)&lifr, 0, sizeof(lifr));
1638      strcpy((caddr_t)&(lifr.lifr_name), ifname);
1639 
1640      if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
1641          return -1;
1642      }
1643 
1644      return  lifr.lifr_flags;
1645 }
1646 
1647 
1648 #endif
1649 
1650