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