1 /*
   2  * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 #include "net_util.h"
  26 #include "NetworkInterface.h"
  27 
  28 #include "java_net_NetworkInterface.h"
  29 
  30 /*
  31  * Windows implementation of the java.net.NetworkInterface native methods.
  32  * This module provides the implementations of getAll, getByName, getByIndex,
  33  * and getByAddress.
  34  *
  35  * Interfaces and addresses are enumerated using the IP helper routines
  36  * GetIfTable, GetIfAddrTable resp. These routines are available on Windows
  37  * 98, NT SP+4, 2000, and XP. They are also available on Windows 95 if
  38  * IE is upgraded to 5.x.
  39  *
  40  * Windows does not have any standard for device names so we are forced
  41  * to use our own convention which is based on the normal Unix naming
  42  * convention ("lo" for the loopback, eth0, eth1, .. for ethernet devices,
  43  * tr0, tr1, .. for token ring, and so on). This convention gives us
  44  * consistency across multiple Windows editions and also consistency with
  45  * Solaris/Linux device names. Note that we always enumerate in index
  46  * order and this ensures consistent device number across invocations.
  47  */
  48 
  49 /* various JNI ids */
  50 
  51 jclass ni_class;            /* NetworkInterface */
  52 
  53 jmethodID ni_ctor;          /* NetworkInterface() */
  54 
  55 jfieldID ni_indexID;        /* NetworkInterface.index */
  56 jfieldID ni_addrsID;        /* NetworkInterface.addrs */
  57 jfieldID ni_bindsID;        /* NetworkInterface.bindings */
  58 jfieldID ni_nameID;         /* NetworkInterface.name */
  59 jfieldID ni_displayNameID;  /* NetworkInterface.displayName */
  60 jfieldID ni_childsID;       /* NetworkInterface.childs */
  61 
  62 jclass ni_ibcls;            /* InterfaceAddress */
  63 jmethodID ni_ibctrID;       /* InterfaceAddress() */
  64 jfieldID ni_ibaddressID;        /* InterfaceAddress.address */
  65 jfieldID ni_ibbroadcastID;      /* InterfaceAddress.broadcast */
  66 jfieldID ni_ibmaskID;           /* InterfaceAddress.maskLength */
  67 
  68 /*
  69  * Support routines to free netif and netaddr lists
  70  */
  71 void free_netif(netif *netifP) {
  72     netif *curr = netifP;
  73     while (curr != NULL) {
  74         if (curr->name != NULL)
  75             free(curr->name);
  76         if (curr->displayName != NULL)
  77             free(curr->displayName);
  78         if (curr->addrs != NULL)
  79             free_netaddr (curr->addrs);
  80         netifP = netifP->next;
  81         free(curr);
  82         curr = netifP;
  83     }
  84 }
  85 
  86 void free_netaddr(netaddr *netaddrP) {
  87     netaddr *curr = netaddrP;
  88     while (curr != NULL) {
  89         netaddrP = netaddrP->next;
  90         free(curr);
  91         curr = netaddrP;
  92     }
  93 }
  94 
  95 /*
  96  * Returns the interface structure from the table with the matching index.
  97  */
  98 MIB_IFROW *getIF(jint index) {
  99     MIB_IFTABLE *tableP;
 100     MIB_IFROW *ifrowP, *ret = NULL;
 101     ULONG size;
 102     DWORD i, count;
 103     jint ifindex;
 104 
 105     /*
 106      * Ask the IP Helper library to enumerate the adapters
 107      */
 108     size = sizeof(MIB_IFTABLE);
 109     tableP = (MIB_IFTABLE *)malloc(size);
 110     if(tableP == NULL)
 111         return NULL;
 112 
 113     count = GetIfTable(tableP, &size, TRUE);
 114     if (count == ERROR_INSUFFICIENT_BUFFER || count == ERROR_BUFFER_OVERFLOW) {
 115         MIB_IFTABLE* newTableP =  (MIB_IFTABLE *)realloc(tableP, size);
 116         if (newTableP == NULL) {
 117             free(tableP);
 118             return NULL;
 119         }
 120         tableP = newTableP;
 121 
 122         count = GetIfTable(tableP, &size, TRUE);
 123     }
 124 
 125     if (count != NO_ERROR) {
 126         free(tableP);
 127         return NULL;
 128     }
 129 
 130     {
 131     ifrowP = tableP->table;
 132     for (i=0; i<tableP->dwNumEntries; i++) {
 133     /*
 134      * Warning: the real index is obtained by GetFriendlyIfIndex()
 135     */
 136         ifindex = GetFriendlyIfIndex(ifrowP->dwIndex);
 137         if (ifindex == index) {
 138           /*
 139            * Create a copy of the entry so that we can free the table.
 140            */
 141             ret = (MIB_IFROW *) malloc(sizeof(MIB_IFROW));
 142             if (ret == NULL) {
 143                 free(tableP);
 144                 return NULL;
 145             }
 146             memcpy(ret, ifrowP, sizeof(MIB_IFROW));
 147             break;
 148         }
 149 
 150         /* onto the next interface */
 151         ifrowP++;
 152       }
 153       free(tableP);
 154     }
 155     return ret;
 156 }
 157 
 158 /*
 159  * Enumerate network interfaces using IP Helper Library routine GetIfTable.
 160  * We use GetIfTable rather than other IP helper routines because it's
 161  * available on 98 & NT SP4+.
 162  *
 163  * Returns the number of interfaces found or -1 if error. If no error
 164  * occurs then netifPP be returned as list of netif structures or NULL
 165  * if no interfaces are found.
 166  */
 167 int enumInterfaces(JNIEnv *env, netif **netifPP)
 168 {
 169     MIB_IFTABLE *tableP;
 170     MIB_IFROW *ifrowP;
 171     ULONG size;
 172     DWORD ret;
 173     int count;
 174     netif *netifP;
 175     DWORD i;
 176     int lo=0, eth=0, tr=0, fddi=0, ppp=0, sl=0, wlan=0, net=0, wlen=0;
 177 
 178     /*
 179      * Ask the IP Helper library to enumerate the adapters
 180      */
 181     size = sizeof(MIB_IFTABLE);
 182     tableP = (MIB_IFTABLE *)malloc(size);
 183     if (tableP == NULL) {
 184         JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
 185         return -1;
 186     }
 187 
 188     ret = GetIfTable(tableP, &size, TRUE);
 189     if (ret == ERROR_INSUFFICIENT_BUFFER || ret == ERROR_BUFFER_OVERFLOW) {
 190         MIB_IFTABLE * newTableP = (MIB_IFTABLE *)realloc(tableP, size);
 191         if (newTableP == NULL) {
 192             free(tableP);
 193             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
 194             return -1;
 195         }
 196         tableP = newTableP;
 197         ret = GetIfTable(tableP, &size, TRUE);
 198     }
 199 
 200     if (ret != NO_ERROR) {
 201         free(tableP);
 202 
 203         JNU_ThrowByName(env, "java/lang/Error",
 204                 "IP Helper Library GetIfTable function failed");
 205 
 206         return -1;
 207     }
 208 
 209     /*
 210      * Iterate through the list of adapters
 211      */
 212     count = 0;
 213     netifP = NULL;
 214 
 215     ifrowP = tableP->table;
 216     for (i=0; i<tableP->dwNumEntries; i++) {
 217         char dev_name[8];
 218         netif *curr;
 219 
 220         /*
 221          * Generate a name for the device as Windows doesn't have any
 222          * real concept of a device name.
 223          */
 224         switch (ifrowP->dwType) {
 225             case MIB_IF_TYPE_ETHERNET:
 226                 _snprintf_s(dev_name, 8, _TRUNCATE, "eth%d", eth++);
 227                 break;
 228 
 229             case MIB_IF_TYPE_TOKENRING:
 230                 _snprintf_s(dev_name, 8, _TRUNCATE, "tr%d", tr++);
 231                 break;
 232 
 233             case MIB_IF_TYPE_FDDI:
 234                 _snprintf_s(dev_name, 8, _TRUNCATE, "fddi%d", fddi++);
 235                 break;
 236 
 237             case MIB_IF_TYPE_LOOPBACK:
 238                 /* There should only be only IPv4 loopback address */
 239                 if (lo > 0) {
 240                     continue;
 241                 }
 242                 strncpy_s(dev_name, 8, "lo", _TRUNCATE);
 243                 lo++;
 244                 break;
 245 
 246             case MIB_IF_TYPE_PPP:
 247                 _snprintf_s(dev_name, 8, _TRUNCATE, "ppp%d", ppp++);
 248                 break;
 249 
 250             case MIB_IF_TYPE_SLIP:
 251                 _snprintf_s(dev_name, 8, _TRUNCATE, "sl%d", sl++);
 252                 break;
 253 
 254             case IF_TYPE_IEEE80211:
 255                 _snprintf_s(dev_name, 8, _TRUNCATE, "wlan%d", wlan++);
 256                 break;
 257 
 258             default:
 259                 _snprintf_s(dev_name, 8, _TRUNCATE, "net%d", net++);
 260         }
 261 
 262         /*
 263          * Allocate a netif structure and space for the name and
 264          * display name (description in this case).
 265          */
 266         curr = (netif *)calloc(1, sizeof(netif));
 267         if (curr != NULL) {
 268             wlen = MultiByteToWideChar(CP_OEMCP, 0, ifrowP->bDescr,
 269                        ifrowP->dwDescrLen, NULL, 0);
 270             if(wlen == 0) {
 271                 // MultiByteToWideChar should not fail
 272                 // But in rare case it fails, we allow 'char' to be displayed
 273                 curr->displayName = (char *)malloc(ifrowP->dwDescrLen + 1);
 274             } else {
 275                 curr->displayName = (wchar_t *)malloc(wlen*(sizeof(wchar_t))+1);
 276             }
 277 
 278             curr->name = (char *)malloc(strlen(dev_name) + 1);
 279 
 280             if (curr->name == NULL || curr->displayName == NULL) {
 281                 if (curr->name) free(curr->name);
 282                 if (curr->displayName) free(curr->displayName);
 283                 free(curr);
 284                 curr = NULL;
 285             }
 286         }
 287         if (curr == NULL) {
 288             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
 289             free_netif(netifP);
 290             free(tableP);
 291             return -1;
 292         }
 293 
 294         /*
 295          * Populate the interface. Note that we need to convert the
 296          * index into its "friendly" value as otherwise we will expose
 297          * 32-bit numbers as index values.
 298          */
 299         strcpy(curr->name, dev_name);
 300         if (wlen == 0) {
 301             // display char type in case of MultiByteToWideChar failure
 302             strncpy(curr->displayName, ifrowP->bDescr, ifrowP->dwDescrLen);
 303             curr->displayName[ifrowP->dwDescrLen] = '\0';
 304         } else {
 305             // call MultiByteToWideChar again to fill curr->displayName
 306             // it should not fail, because we have called it once before
 307             if (MultiByteToWideChar(CP_OEMCP, 0, ifrowP->bDescr,
 308                    ifrowP->dwDescrLen, curr->displayName, wlen) == 0) {
 309                 JNU_ThrowByName(env, "java/lang/Error",
 310                        "Cannot get multibyte char for interface display name");
 311                 free_netif(netifP);
 312                 free(tableP);
 313                 free(curr->name);
 314                 free(curr->displayName);
 315                 free(curr);
 316                 return -1;
 317             } else {
 318                 curr->displayName[wlen*(sizeof(wchar_t))] = '\0';
 319                 curr->dNameIsUnicode = TRUE;
 320             }
 321         }
 322 
 323         curr->dwIndex = ifrowP->dwIndex;
 324         curr->ifType = ifrowP->dwType;
 325         curr->index = GetFriendlyIfIndex(ifrowP->dwIndex);
 326 
 327         /*
 328          * Put the interface at tail of list as GetIfTable(,,TRUE) is
 329          * returning the interfaces in index order.
 330          */
 331         count++;
 332         if (netifP == NULL) {
 333             netifP = curr;
 334         } else {
 335             netif *tail = netifP;
 336             while (tail->next != NULL) {
 337                 tail = tail->next;
 338             }
 339             tail->next = curr;
 340         }
 341 
 342         /* onto the next interface */
 343         ifrowP++;
 344     }
 345 
 346     /*
 347      * Free the interface table and return the interface list
 348      */
 349     if (tableP) {
 350         free(tableP);
 351     }
 352     *netifPP = netifP;
 353     return count;
 354 }
 355 
 356 /*
 357  * Enumerate the IP addresses on an interface using the IP helper library
 358  * routine GetIfAddrTable and matching based on the index name. There are
 359  * more efficient routines but we use GetIfAddrTable because it's avaliable
 360  * on 98 and NT.
 361  *
 362  * Returns the count of addresses, or -1 if error. If no error occurs then
 363  * netaddrPP will return a list of netaddr structures with the IP addresses.
 364  */
 365 int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP)
 366 {
 367     MIB_IPADDRTABLE *tableP;
 368     ULONG size;
 369     DWORD ret;
 370     DWORD i;
 371     netaddr *netaddrP;
 372     int count = 0;
 373     unsigned long mask;
 374 
 375     /*
 376      * Use GetIpAddrTable to enumerate the IP Addresses
 377      */
 378     size = sizeof(MIB_IPADDRTABLE);
 379     tableP = (MIB_IPADDRTABLE *)malloc(size);
 380     if (tableP == NULL) {
 381         JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
 382         return -1;
 383     }
 384 
 385     ret = GetIpAddrTable(tableP, &size, FALSE);
 386     if (ret == ERROR_INSUFFICIENT_BUFFER || ret == ERROR_BUFFER_OVERFLOW) {
 387         MIB_IPADDRTABLE * newTableP = (MIB_IPADDRTABLE *)realloc(tableP, size);
 388         if (newTableP == NULL) {
 389             free(tableP);
 390             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
 391             return -1;
 392         }
 393         tableP = newTableP;
 394 
 395         ret = GetIpAddrTable(tableP, &size, FALSE);
 396     }
 397     if (ret != NO_ERROR) {
 398         if (tableP) {
 399             free(tableP);
 400         }
 401         JNU_ThrowByName(env, "java/lang/Error",
 402                 "IP Helper Library GetIpAddrTable function failed");
 403         return -1;
 404     }
 405 
 406     /*
 407      * Iterate through the table to find the addresses with the
 408      * matching dwIndex. Ignore 0.0.0.0 addresses.
 409      */
 410     count = 0;
 411     netaddrP = NULL;
 412 
 413     i = 0;
 414     while (i<tableP->dwNumEntries) {
 415         if (tableP->table[i].dwIndex == netifP->dwIndex &&
 416             tableP->table[i].dwAddr != 0) {
 417 
 418             netaddr *curr = (netaddr *)malloc(sizeof(netaddr));
 419             if (curr == NULL) {
 420                 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
 421                 free_netaddr(netaddrP);
 422                 free(tableP);
 423                 return -1;
 424             }
 425 
 426             curr->addr.sa4.sin_family = AF_INET;
 427             curr->addr.sa4.sin_addr.s_addr = tableP->table[i].dwAddr;
 428             /*
 429              * Get netmask / broadcast address
 430              */
 431             switch (netifP->ifType) {
 432             case MIB_IF_TYPE_ETHERNET:
 433             case MIB_IF_TYPE_TOKENRING:
 434             case MIB_IF_TYPE_FDDI:
 435             case MIB_IF_TYPE_LOOPBACK:
 436             case IF_TYPE_IEEE80211:
 437               /**
 438                * Contrary to what it seems to indicate, dwBCastAddr doesn't
 439                * contain the broadcast address but 0 or 1 depending on whether
 440                * the broadcast address should set the bits of the host part
 441                * to 0 or 1.
 442                * Yes, I know it's stupid, but what can I say, it's MSFTs API.
 443                */
 444               curr->brdcast.sa4.sin_family = AF_INET;
 445               if (tableP->table[i].dwBCastAddr == 1)
 446                 curr->brdcast.sa4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask) | (0xffffffff ^ tableP->table[i].dwMask);
 447               else
 448                 curr->brdcast.sa4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask);
 449               mask = ntohl(tableP->table[i].dwMask);
 450               curr->mask = 0;
 451               while (mask) {
 452                 mask <<= 1;
 453                 curr->mask++;
 454               }
 455               break;
 456             case MIB_IF_TYPE_PPP:
 457             case MIB_IF_TYPE_SLIP:
 458             default:
 459               /**
 460                * these don't have broadcast/subnet
 461                */
 462               curr->mask = -1;
 463                 break;
 464             }
 465 
 466             curr->next = netaddrP;
 467             netaddrP = curr;
 468             count++;
 469         }
 470         i++;
 471     }
 472 
 473     *netaddrPP = netaddrP;
 474     free(tableP);
 475     return count;
 476 }
 477 
 478 /*
 479  * Class:     java_net_NetworkInterface
 480  * Method:    init
 481  * Signature: ()V
 482  */
 483 JNIEXPORT void JNICALL
 484 Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls)
 485 {
 486     /*
 487      * Get the various JNI ids that we require
 488      */
 489     ni_class = (*env)->NewGlobalRef(env, cls);
 490     CHECK_NULL(ni_class);
 491     ni_nameID = (*env)->GetFieldID(env, ni_class, "name", "Ljava/lang/String;");
 492     CHECK_NULL(ni_nameID);
 493     ni_displayNameID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;");
 494     CHECK_NULL(ni_displayNameID);
 495     ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
 496     CHECK_NULL(ni_indexID);
 497     ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;");
 498     CHECK_NULL(ni_addrsID);
 499     ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;");
 500     CHECK_NULL(ni_bindsID);
 501     ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;");
 502     CHECK_NULL(ni_childsID);
 503     ni_ctor = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
 504     CHECK_NULL(ni_ctor);
 505     ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
 506     CHECK_NULL(ni_ibcls);
 507     ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
 508     CHECK_NULL(ni_ibcls);
 509     ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
 510     CHECK_NULL(ni_ibctrID);
 511     ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;");
 512     CHECK_NULL(ni_ibaddressID);
 513     ni_ibbroadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;");
 514     CHECK_NULL(ni_ibbroadcastID);
 515     ni_ibmaskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
 516     CHECK_NULL(ni_ibmaskID);
 517 
 518     initInetAddressIDs(env);
 519 }
 520 
 521 /*
 522  * Create a NetworkInterface object, populate the name and index, and
 523  * populate the InetAddress array based on the IP addresses for this
 524  * interface.
 525  */
 526 jobject createNetworkInterface
 527     (JNIEnv *env, netif *ifs, int netaddrCount, netaddr *netaddrP)
 528 {
 529     jobject netifObj;
 530     jobject name, displayName;
 531     jobjectArray addrArr, bindsArr, childArr;
 532     netaddr *addrs;
 533     jint addr_index;
 534     jint bind_index;
 535 
 536     /*
 537      * Create a NetworkInterface object and populate it
 538      */
 539     netifObj = (*env)->NewObject(env, ni_class, ni_ctor);
 540     CHECK_NULL_RETURN(netifObj, NULL);
 541     name = (*env)->NewStringUTF(env, ifs->name);
 542     CHECK_NULL_RETURN(name, NULL);
 543     if (ifs->dNameIsUnicode) {
 544         displayName = (*env)->NewString(env, (PWCHAR)ifs->displayName,
 545                                        (jsize)wcslen ((PWCHAR)ifs->displayName));
 546     } else {
 547         displayName = (*env)->NewStringUTF(env, ifs->displayName);
 548     }
 549     CHECK_NULL_RETURN(displayName, NULL);
 550     (*env)->SetObjectField(env, netifObj, ni_nameID, name);
 551     (*env)->SetObjectField(env, netifObj, ni_displayNameID, displayName);
 552     (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
 553 
 554     /*
 555      * Get the IP addresses for this interface if necessary
 556      * Note that 0 is a valid number of addresses.
 557      */
 558     if (netaddrCount < 0) {
 559         netaddrCount = enumAddresses_win(env, ifs, &netaddrP);
 560         if (netaddrCount == -1) {
 561             return NULL;
 562         }
 563     }
 564     addrArr = (*env)->NewObjectArray(env, netaddrCount, ia_class, NULL);
 565     if (addrArr == NULL) {
 566         free_netaddr(netaddrP);
 567         return NULL;
 568     }
 569 
 570     bindsArr = (*env)->NewObjectArray(env, netaddrCount, ni_ibcls, NULL);
 571     if (bindsArr == NULL) {
 572       free_netaddr(netaddrP);
 573       return NULL;
 574     }
 575     addrs = netaddrP;
 576     addr_index = 0;
 577     bind_index = 0;
 578     while (addrs != NULL) {
 579         jobject iaObj, ia2Obj;
 580         jobject ibObj = NULL;
 581         if (addrs->addr.sa.sa_family == AF_INET) {
 582             iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 583             if (iaObj == NULL) {
 584                 free_netaddr(netaddrP);
 585                 return NULL;
 586             }
 587             /* default ctor will set family to AF_INET */
 588 
 589             setInetAddress_addr(env, iaObj, ntohl(addrs->addr.sa4.sin_addr.s_addr));
 590             if ((*env)->ExceptionCheck(env)) {
 591                 free_netaddr(netaddrP);
 592                 return NULL;
 593             }
 594             if (addrs->mask != -1) {
 595               ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
 596               if (ibObj == NULL) {
 597                 free_netaddr(netaddrP);
 598                 return NULL;
 599               }
 600               (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
 601               ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 602               if (ia2Obj == NULL) {
 603                 free_netaddr(netaddrP);
 604                 return NULL;
 605               }
 606               setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.sa4.sin_addr.s_addr));
 607               if ((*env)->ExceptionCheck(env)) {
 608                   free_netaddr(netaddrP);
 609                   return NULL;
 610               }
 611               (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj);
 612               (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
 613               (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
 614             }
 615         } else /* AF_INET6 */ {
 616             int scope;
 617             iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
 618             if (iaObj) {
 619                 jboolean ret = setInet6Address_ipaddress(env, iaObj,  (jbyte *)&(addrs->addr.sa6.sin6_addr.s6_addr));
 620                 if (ret == JNI_FALSE) {
 621                     free_netaddr(netaddrP);
 622                     return NULL;
 623                 }
 624 
 625                 scope = addrs->addr.sa6.sin6_scope_id;
 626                 if (scope != 0) { /* zero is default value, no need to set */
 627                     setInet6Address_scopeid(env, iaObj, scope);
 628                     setInet6Address_scopeifname(env, iaObj, netifObj);
 629                 }
 630                 ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
 631                 if (ibObj == NULL) {
 632                   free_netaddr(netaddrP);
 633                   return NULL;
 634                 }
 635                 (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
 636                 (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
 637                 (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
 638             }
 639         }
 640         (*env)->SetObjectArrayElement(env, addrArr, addr_index, iaObj);
 641         addrs = addrs->next;
 642         addr_index++;
 643     }
 644     (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
 645     (*env)->SetObjectField(env, netifObj, ni_bindsID, bindsArr);
 646 
 647     free_netaddr(netaddrP);
 648 
 649     /*
 650      * Windows doesn't have virtual interfaces, so child array
 651      * is always empty.
 652      */
 653     childArr = (*env)->NewObjectArray(env, 0, ni_class, NULL);
 654     if (childArr == NULL) {
 655       return NULL;
 656     }
 657     (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
 658 
 659     /* return the NetworkInterface */
 660     return netifObj;
 661 }
 662 
 663 /*
 664  * Class:     java_net_NetworkInterface
 665  * Method:    getByName0
 666  * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
 667  */
 668 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0
 669     (JNIEnv *env, jclass cls, jstring name)
 670 {
 671     netif *ifList, *curr;
 672     jboolean isCopy;
 673     const char *name_utf;
 674     jobject netifObj = NULL;
 675 
 676     // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 677     if (ipv6_available()) {
 678         return Java_java_net_NetworkInterface_getByName0_XP (env, cls, name);
 679     }
 680 
 681     /* get the list of interfaces */
 682     if (enumInterfaces(env, &ifList) < 0) {
 683         return NULL;
 684     }
 685 
 686     /* get the name as a C string */
 687     name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
 688     if (name_utf != NULL) {
 689 
 690         /* Search by name */
 691         curr = ifList;
 692         while (curr != NULL) {
 693             if (strcmp(name_utf, curr->name) == 0) {
 694                 break;
 695             }
 696             curr = curr->next;
 697         }
 698 
 699         /* if found create a NetworkInterface */
 700         if (curr != NULL) {;
 701             netifObj = createNetworkInterface(env, curr, -1, NULL);
 702         }
 703 
 704         /* release the UTF string */
 705         (*env)->ReleaseStringUTFChars(env, name, name_utf);
 706     } else {
 707         if (!(*env)->ExceptionCheck(env))
 708             JNU_ThrowOutOfMemoryError(env, NULL);
 709     }
 710 
 711     /* release the interface list */
 712     free_netif(ifList);
 713 
 714     return netifObj;
 715 }
 716 
 717 /*
 718  * Class:     NetworkInterface
 719  * Method:    getByIndex0
 720  * Signature: (I)LNetworkInterface;
 721  */
 722 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0
 723   (JNIEnv *env, jclass cls, jint index)
 724 {
 725     netif *ifList, *curr;
 726     jobject netifObj = NULL;
 727 
 728     // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 729     if (ipv6_available()) {
 730         return Java_java_net_NetworkInterface_getByIndex0_XP (env, cls, index);
 731     }
 732 
 733     /* get the list of interfaces */
 734     if (enumInterfaces(env, &ifList) < 0) {
 735         return NULL;
 736     }
 737 
 738     /* search by index */
 739     curr = ifList;
 740     while (curr != NULL) {
 741         if (index == curr->index) {
 742             break;
 743         }
 744         curr = curr->next;
 745     }
 746 
 747     /* if found create a NetworkInterface */
 748     if (curr != NULL) {
 749         netifObj = createNetworkInterface(env, curr, -1, NULL);
 750     }
 751 
 752     /* release the interface list */
 753     free_netif(ifList);
 754 
 755     return netifObj;
 756 }
 757 
 758 /*
 759  * Class:     java_net_NetworkInterface
 760  * Method:    getByInetAddress0
 761  * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
 762  */
 763 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
 764     (JNIEnv *env, jclass cls, jobject iaObj)
 765 {
 766     netif *ifList, *curr;
 767     jobject netifObj = NULL;
 768     jint addr = getInetAddress_addr(env, iaObj);
 769     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
 770 
 771     // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 772     if (ipv6_available()) {
 773         return Java_java_net_NetworkInterface_getByInetAddress0_XP (env, cls, iaObj);
 774     }
 775 
 776     /* get the list of interfaces */
 777     if (enumInterfaces(env, &ifList) < 0) {
 778         return NULL;
 779     }
 780 
 781     /*
 782      * Enumerate the addresses on each interface until we find a
 783      * matching address.
 784      */
 785     curr = ifList;
 786     while (curr != NULL) {
 787         int count;
 788         netaddr *addrList;
 789         netaddr *addrP;
 790 
 791         /* enumerate the addresses on this interface */
 792         count = enumAddresses_win(env, curr, &addrList);
 793         if (count < 0) {
 794             free_netif(ifList);
 795             return NULL;
 796         }
 797 
 798         /* iterate through each address */
 799         addrP = addrList;
 800 
 801         while (addrP != NULL) {
 802             if ((unsigned long)addr == ntohl(addrP->addr.sa4.sin_addr.s_addr)) {
 803                 break;
 804             }
 805             addrP = addrP->next;
 806         }
 807 
 808         /*
 809          * Address matched so create NetworkInterface for this interface
 810          * and address list.
 811          */
 812         if (addrP != NULL) {
 813             /* createNetworkInterface will free addrList */
 814             netifObj = createNetworkInterface(env, curr, count, addrList);
 815             break;
 816         }
 817 
 818         /* on next interface */
 819         curr = curr->next;
 820     }
 821 
 822     /* release the interface list */
 823     free_netif(ifList);
 824 
 825     return netifObj;
 826 }
 827 
 828 /*
 829  * Class:     java_net_NetworkInterface
 830  * Method:    getAll
 831  * Signature: ()[Ljava/net/NetworkInterface;
 832  */
 833 JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll
 834     (JNIEnv *env, jclass cls)
 835 {
 836     int count;
 837     netif *ifList = NULL, *curr;
 838     jobjectArray netIFArr;
 839     jint arr_index;
 840 
 841     // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 842     if (ipv6_available()) {
 843         return Java_java_net_NetworkInterface_getAll_XP (env, cls);
 844     }
 845 
 846     /*
 847      * Get list of interfaces
 848      */
 849     count = enumInterfaces(env, &ifList);
 850     if (count < 0) {
 851         return NULL;
 852     }
 853 
 854     /* allocate a NetworkInterface array */
 855     netIFArr = (*env)->NewObjectArray(env, count, cls, NULL);
 856     if (netIFArr == NULL) {
 857         free_netif(ifList);
 858         return NULL;
 859     }
 860 
 861     /*
 862      * Iterate through the interfaces, create a NetworkInterface instance
 863      * for each array element and populate the object.
 864      */
 865     curr = ifList;
 866     arr_index = 0;
 867     while (curr != NULL) {
 868         jobject netifObj;
 869 
 870         netifObj = createNetworkInterface(env, curr, -1, NULL);
 871         if (netifObj == NULL) {
 872             free_netif(ifList);
 873             return NULL;
 874         }
 875 
 876         /* put the NetworkInterface into the array */
 877         (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
 878 
 879         curr = curr->next;
 880     }
 881 
 882     /* release the interface list */
 883     free_netif(ifList);
 884 
 885     return netIFArr;
 886 }
 887 
 888 /*
 889  * Class:     java_net_NetworkInterface
 890  * Method:    isUp0
 891  * Signature: (Ljava/lang/String;)Z
 892  */
 893 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0
 894     (JNIEnv *env, jclass cls, jstring name, jint index) {
 895   jboolean ret = JNI_FALSE;
 896 
 897   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 898   if (ipv6_available()) {
 899     return Java_java_net_NetworkInterface_isUp0_XP(env, cls, name, index);
 900   } else {
 901     MIB_IFROW *ifRowP;
 902     ifRowP = getIF(index);
 903     if (ifRowP != NULL) {
 904       ret = ifRowP->dwAdminStatus == MIB_IF_ADMIN_STATUS_UP &&
 905             (ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL ||
 906              ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED);
 907       free(ifRowP);
 908     }
 909   }
 910     return ret;
 911 }
 912 
 913 /*
 914  * Class:     java_net_NetworkInterface
 915  * Method:    isP2P0
 916  * Signature: (Ljava/lang/String;I)Z
 917  */
 918 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0
 919     (JNIEnv *env, jclass cls, jstring name, jint index) {
 920   MIB_IFROW *ifRowP;
 921   jboolean ret = JNI_FALSE;
 922 
 923   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 924   if (ipv6_available()) {
 925     return Java_java_net_NetworkInterface_isP2P0_XP(env, cls, name, index);
 926   } else {
 927     ifRowP = getIF(index);
 928     if (ifRowP != NULL) {
 929       switch(ifRowP->dwType) {
 930       case MIB_IF_TYPE_PPP:
 931       case MIB_IF_TYPE_SLIP:
 932         ret = JNI_TRUE;
 933         break;
 934       }
 935       free(ifRowP);
 936     }
 937   }
 938   return ret;
 939 }
 940 
 941 /*
 942  * Class:     java_net_NetworkInterface
 943  * Method:    isLoopback0
 944  * Signature: (Ljava/lang/String;I)Z
 945  */
 946 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0
 947     (JNIEnv *env, jclass cls, jstring name, jint index) {
 948   MIB_IFROW *ifRowP;
 949   jboolean ret = JNI_FALSE;
 950 
 951   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 952   if (ipv6_available()) {
 953     return Java_java_net_NetworkInterface_isLoopback0_XP(env, cls, name, index);
 954   } else {
 955     ifRowP = getIF(index);
 956     if (ifRowP != NULL) {
 957       if (ifRowP->dwType == MIB_IF_TYPE_LOOPBACK)
 958         ret = JNI_TRUE;
 959       free(ifRowP);
 960     }
 961     return ret;
 962   }
 963 }
 964 
 965 /*
 966  * Class:     java_net_NetworkInterface
 967  * Method:    supportsMulticast0
 968  * Signature: (Ljava/lang/String;I)Z
 969  */
 970 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0
 971     (JNIEnv *env, jclass cls, jstring name, jint index) {
 972     return Java_java_net_NetworkInterface_supportsMulticast0_XP(env, cls,
 973                                                                name, index);
 974 }
 975 
 976 /*
 977  * Class:     java_net_NetworkInterface
 978  * Method:    getMacAddr0
 979  * Signature: ([bLjava/lang/String;I)[b
 980  */
 981 JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0
 982     (JNIEnv *env, jclass class, jbyteArray addrArray, jstring name, jint index) {
 983   jbyteArray ret = NULL;
 984   int len;
 985   MIB_IFROW *ifRowP;
 986 
 987   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 988   if (ipv6_available()) {
 989     return Java_java_net_NetworkInterface_getMacAddr0_XP(env, class, name, index);
 990   } else {
 991     ifRowP = getIF(index);
 992     if (ifRowP != NULL) {
 993       switch(ifRowP->dwType) {
 994       case MIB_IF_TYPE_ETHERNET:
 995       case MIB_IF_TYPE_TOKENRING:
 996       case MIB_IF_TYPE_FDDI:
 997       case IF_TYPE_IEEE80211:
 998         len = ifRowP->dwPhysAddrLen;
 999         if (len > 0) {
1000             ret = (*env)->NewByteArray(env, len);
1001             if (!IS_NULL(ret)) {
1002               (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr);
1003             }
1004         }
1005         break;
1006       }
1007       free(ifRowP);
1008     }
1009     return ret;
1010   }
1011 }
1012 
1013 /*
1014  * Class:       java_net_NetworkInterface
1015  * Method:      getMTU0
1016  * Signature:   ([bLjava/lang/String;I)I
1017  */
1018 JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0
1019     (JNIEnv *env, jclass class, jstring name, jint index) {
1020   jint ret = -1;
1021   MIB_IFROW *ifRowP;
1022 
1023   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
1024   if (ipv6_available()) {
1025     return Java_java_net_NetworkInterface_getMTU0_XP(env, class, name, index);
1026   } else {
1027     ifRowP = getIF(index);
1028     if (ifRowP != NULL) {
1029       ret = ifRowP->dwMtu;
1030       free(ifRowP);
1031     }
1032     return ret;
1033   }
1034 }