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