1 /*
   2  * Copyright 2000-2009 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 #include <errno.h>
  27 #include <strings.h>
  28 #include <netinet/in.h>
  29 #include <stdlib.h>
  30 #include <string.h>
  31 #include <sys/types.h>
  32 #include <sys/socket.h>
  33 #include <arpa/inet.h>
  34 #include <net/if.h>
  35 #include <net/if_arp.h>
  36 #ifdef __solaris__
  37 #include <sys/dlpi.h>
  38 #include <fcntl.h>
  39 #include <stropts.h>
  40 #endif
  41 #ifdef __linux__
  42 #include <sys/ioctl.h>
  43 #include <bits/ioctls.h>
  44 #include <linux/sockios.h>
  45 #include <sys/utsname.h>
  46 #include <stdio.h>
  47 #else
  48 #include <sys/sockio.h>
  49 #endif
  50 
  51 #ifdef __linux__
  52 #define ifr_index ifr_ifindex
  53 #define _PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
  54 #endif
  55 
  56 #include "jvm.h"
  57 #include "jni_util.h"
  58 #include "net_util.h"
  59 
  60 typedef struct _netaddr  {
  61     struct sockaddr *addr;
  62     struct sockaddr *brdcast;
  63     short mask;
  64     int family; /* to make searches simple */
  65     struct _netaddr *next;
  66 } netaddr;
  67 
  68 typedef struct _netif {
  69     char *name;
  70     int index;
  71     char virtual;
  72     netaddr *addr;
  73     struct _netif *childs;
  74     struct _netif *next;
  75 } netif;
  76 
  77 /************************************************************************
  78  * NetworkInterface
  79  */
  80 
  81 #include "java_net_NetworkInterface.h"
  82 
  83 /************************************************************************
  84  * NetworkInterface
  85  */
  86 jclass ni_class;
  87 jfieldID ni_nameID;
  88 jfieldID ni_indexID;
  89 jfieldID ni_descID;
  90 jfieldID ni_addrsID;
  91 jfieldID ni_bindsID;
  92 jfieldID ni_virutalID;
  93 jfieldID ni_childsID;
  94 jfieldID ni_parentID;
  95 jmethodID ni_ctrID;
  96 



  97 static jclass ni_ibcls;


  98 static jmethodID ni_ibctrID;



  99 static jfieldID ni_ibaddressID;
 100 static jfieldID ni_ib4broadcastID;
 101 static jfieldID ni_ib4maskID;
 102 
 103 static jobject createNetworkInterface(JNIEnv *env, netif *ifs);
 104 
 105 static netif *enumInterfaces(JNIEnv *env);
 106 static netif *enumIPv4Interfaces(JNIEnv *env, netif *ifs);
 107 #ifdef AF_INET6
 108 static netif *enumIPv6Interfaces(JNIEnv *env, netif *ifs);
 109 #endif
 110 
 111 static netif *addif(JNIEnv *env, netif *ifs, char *if_name, int index,
 112                     int family, struct sockaddr *new_addrP, int new_addrlen,
 113                     short prefix);
 114 static void freeif(netif *ifs);
 115 static struct sockaddr *getBroadcast(JNIEnv *env, const char *ifname);
 116 static short getSubnet(JNIEnv *env, const char *ifname);
 117 
 118 /*
 119  * Class:     java_net_NetworkInterface
 120  * Method:    init
 121  * Signature: ()V
 122  */
 123 JNIEXPORT void JNICALL
 124 Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls) {
 125     if (ni_ib4maskID == NULL) {
 126         ni_class = (*env)->FindClass(env,"java/net/NetworkInterface");
 127         ni_class = (*env)->NewGlobalRef(env, ni_class);
 128         ni_nameID = (*env)->GetFieldID(env, ni_class,"name", "Ljava/lang/String;");
 129         ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
 130         ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;");
 131         ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;");
 132         ni_descID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;");
 133         ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z");
 134         ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;");
 135         ni_parentID = (*env)->GetFieldID(env, ni_class, "parent", "Ljava/net/NetworkInterface;");
 136         ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
 137 






 138         ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
 139         ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);


 140         ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");



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