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         // this different error code is to handle the case when we call 
 206         // GetIpAddrTable in pure IPv6 environment
 207         return -2;
 208     }
 209 
 210     /*
 211      * Iterate through the list of adapters
 212      */
 213     count = 0;
 214     netifP = NULL;
 215 
 216     ifrowP = tableP->table;
 217     for (i=0; i<tableP->dwNumEntries; i++) {
 218         char dev_name[8];
 219         netif *curr;
 220 
 221         /*
 222          * Generate a name for the device as Windows doesn't have any
 223          * real concept of a device name.
 224          */
 225         switch (ifrowP->dwType) {
 226             case MIB_IF_TYPE_ETHERNET:
 227                 _snprintf_s(dev_name, 8, _TRUNCATE, "eth%d", eth++);
 228                 break;
 229 
 230             case MIB_IF_TYPE_TOKENRING:
 231                 _snprintf_s(dev_name, 8, _TRUNCATE, "tr%d", tr++);
 232                 break;
 233 
 234             case MIB_IF_TYPE_FDDI:
 235                 _snprintf_s(dev_name, 8, _TRUNCATE, "fddi%d", fddi++);
 236                 break;
 237 
 238             case MIB_IF_TYPE_LOOPBACK:
 239                 /* There should only be only IPv4 loopback address */
 240                 if (lo > 0) {
 241                     continue;
 242                 }
 243                 strncpy_s(dev_name, 8, "lo", _TRUNCATE);
 244                 lo++;
 245                 break;
 246 
 247             case MIB_IF_TYPE_PPP:
 248                 _snprintf_s(dev_name, 8, _TRUNCATE, "ppp%d", ppp++);
 249                 break;
 250 
 251             case MIB_IF_TYPE_SLIP:
 252                 _snprintf_s(dev_name, 8, _TRUNCATE, "sl%d", sl++);
 253                 break;
 254 
 255             case IF_TYPE_IEEE80211:
 256                 _snprintf_s(dev_name, 8, _TRUNCATE, "wlan%d", wlan++);
 257                 break;
 258 
 259             default:
 260                 _snprintf_s(dev_name, 8, _TRUNCATE, "net%d", net++);
 261         }
 262 
 263         /*
 264          * Allocate a netif structure and space for the name and
 265          * display name (description in this case).
 266          */
 267         curr = (netif *)calloc(1, sizeof(netif));
 268         if (curr != NULL) {
 269             wlen = MultiByteToWideChar(CP_OEMCP, 0, ifrowP->bDescr,
 270                        ifrowP->dwDescrLen, NULL, 0);
 271             if(wlen == 0) {
 272                 // MultiByteToWideChar should not fail
 273                 // But in rare case it fails, we allow 'char' to be displayed
 274                 curr->displayName = (char *)malloc(ifrowP->dwDescrLen + 1);
 275             } else {
 276                 curr->displayName = (wchar_t *)malloc(wlen*(sizeof(wchar_t))+1);
 277             }
 278 
 279             curr->name = (char *)malloc(strlen(dev_name) + 1);
 280 
 281             if (curr->name == NULL || curr->displayName == NULL) {
 282                 if (curr->name) free(curr->name);
 283                 if (curr->displayName) free(curr->displayName);
 284                 free(curr);
 285                 curr = NULL;
 286             }
 287         }
 288         if (curr == NULL) {
 289             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
 290             free_netif(netifP);
 291             free(tableP);
 292             return -1;
 293         }
 294 
 295         /*
 296          * Populate the interface. Note that we need to convert the
 297          * index into its "friendly" value as otherwise we will expose
 298          * 32-bit numbers as index values.
 299          */
 300         strcpy(curr->name, dev_name);
 301         if (wlen == 0) {
 302             // display char type in case of MultiByteToWideChar failure
 303             strncpy(curr->displayName, ifrowP->bDescr, ifrowP->dwDescrLen);
 304             curr->displayName[ifrowP->dwDescrLen] = '\0';
 305         } else {
 306             // call MultiByteToWideChar again to fill curr->displayName
 307             // it should not fail, because we have called it once before
 308             if (MultiByteToWideChar(CP_OEMCP, 0, ifrowP->bDescr,
 309                    ifrowP->dwDescrLen, curr->displayName, wlen) == 0) {
 310                 JNU_ThrowByName(env, "java/lang/Error",
 311                        "Cannot get multibyte char for interface display name");
 312                 free_netif(netifP);
 313                 free(tableP);
 314                 free(curr->name);
 315                 free(curr->displayName);
 316                 free(curr);
 317                 return -1;
 318             } else {
 319                 curr->displayName[wlen*(sizeof(wchar_t))] = '\0';
 320                 curr->dNameIsUnicode = TRUE;
 321             }
 322         }
 323 
 324         curr->dwIndex = ifrowP->dwIndex;
 325         curr->ifType = ifrowP->dwType;
 326         curr->index = GetFriendlyIfIndex(ifrowP->dwIndex);
 327 
 328         /*
 329          * Put the interface at tail of list as GetIfTable(,,TRUE) is
 330          * returning the interfaces in index order.
 331          */
 332         count++;
 333         if (netifP == NULL) {
 334             netifP = curr;
 335         } else {
 336             netif *tail = netifP;
 337             while (tail->next != NULL) {
 338                 tail = tail->next;
 339             }
 340             tail->next = curr;
 341         }
 342 
 343         /* onto the next interface */
 344         ifrowP++;
 345     }
 346 
 347     /*
 348      * Free the interface table and return the interface list
 349      */
 350     if (tableP) {
 351         free(tableP);
 352     }
 353     *netifPP = netifP;
 354     return count;
 355 }
 356 
 357 /*
 358  * Enumerate the IP addresses on an interface using the IP helper library
 359  * routine GetIfAddrTable and matching based on the index name. There are
 360  * more efficient routines but we use GetIfAddrTable because it's avaliable
 361  * on 98 and NT.
 362  *
 363  * Returns the count of addresses, or -1 if error. If no error occurs then
 364  * netaddrPP will return a list of netaddr structures with the IP addresses.
 365  */
 366 int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP)
 367 {
 368     MIB_IPADDRTABLE *tableP;
 369     ULONG size;
 370     DWORD ret;
 371     DWORD i;
 372     netaddr *netaddrP;
 373     int count = 0;
 374     unsigned long mask;
 375 
 376     /*
 377      * Use GetIpAddrTable to enumerate the IP Addresses
 378      */
 379     size = sizeof(MIB_IPADDRTABLE);
 380     tableP = (MIB_IPADDRTABLE *)malloc(size);
 381     if (tableP == NULL) {
 382         JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
 383         return -1;
 384     }
 385 
 386     ret = GetIpAddrTable(tableP, &size, FALSE);
 387     if (ret == ERROR_INSUFFICIENT_BUFFER || ret == ERROR_BUFFER_OVERFLOW) {
 388         MIB_IPADDRTABLE * newTableP = (MIB_IPADDRTABLE *)realloc(tableP, size);
 389         if (newTableP == NULL) {
 390             free(tableP);
 391             JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
 392             return -1;
 393         }
 394         tableP = newTableP;
 395 
 396         ret = GetIpAddrTable(tableP, &size, FALSE);
 397     }
 398     if (ret != NO_ERROR) {
 399         if (tableP) {
 400             free(tableP);
 401         }
 402         JNU_ThrowByName(env, "java/lang/Error",
 403                 "IP Helper Library GetIpAddrTable function failed");
 404         // this different error code is to handle the case when we call
 405         // GetIpAddrTable in pure IPv6 environment
 406         return -2;
 407     }
 408 
 409     /*
 410      * Iterate through the table to find the addresses with the
 411      * matching dwIndex. Ignore 0.0.0.0 addresses.
 412      */
 413     count = 0;
 414     netaddrP = NULL;
 415 
 416     i = 0;
 417     while (i<tableP->dwNumEntries) {
 418         if (tableP->table[i].dwIndex == netifP->dwIndex &&
 419             tableP->table[i].dwAddr != 0) {
 420 
 421             netaddr *curr = (netaddr *)malloc(sizeof(netaddr));
 422             if (curr == NULL) {
 423                 JNU_ThrowOutOfMemoryError(env, "Native heap allocation failure");
 424                 free_netaddr(netaddrP);
 425                 free(tableP);
 426                 return -1;
 427             }
 428 
 429             curr->addr.sa4.sin_family = AF_INET;
 430             curr->addr.sa4.sin_addr.s_addr = tableP->table[i].dwAddr;
 431             /*
 432              * Get netmask / broadcast address
 433              */
 434             switch (netifP->ifType) {
 435             case MIB_IF_TYPE_ETHERNET:
 436             case MIB_IF_TYPE_TOKENRING:
 437             case MIB_IF_TYPE_FDDI:
 438             case MIB_IF_TYPE_LOOPBACK:
 439             case IF_TYPE_IEEE80211:
 440               /**
 441                * Contrary to what it seems to indicate, dwBCastAddr doesn't
 442                * contain the broadcast address but 0 or 1 depending on whether
 443                * the broadcast address should set the bits of the host part
 444                * to 0 or 1.
 445                * Yes, I know it's stupid, but what can I say, it's MSFTs API.
 446                */
 447               curr->brdcast.sa4.sin_family = AF_INET;
 448               if (tableP->table[i].dwBCastAddr == 1)
 449                 curr->brdcast.sa4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask) | (0xffffffff ^ tableP->table[i].dwMask);
 450               else
 451                 curr->brdcast.sa4.sin_addr.s_addr = (tableP->table[i].dwAddr & tableP->table[i].dwMask);
 452               mask = ntohl(tableP->table[i].dwMask);
 453               curr->mask = 0;
 454               while (mask) {
 455                 mask <<= 1;
 456                 curr->mask++;
 457               }
 458               break;
 459             case MIB_IF_TYPE_PPP:
 460             case MIB_IF_TYPE_SLIP:
 461             default:
 462               /**
 463                * these don't have broadcast/subnet
 464                */
 465               curr->mask = -1;
 466                 break;
 467             }
 468 
 469             curr->next = netaddrP;
 470             netaddrP = curr;
 471             count++;
 472         }
 473         i++;
 474     }
 475 
 476     *netaddrPP = netaddrP;
 477     free(tableP);
 478     return count;
 479 }
 480 
 481 /*
 482  * Class:     java_net_NetworkInterface
 483  * Method:    init
 484  * Signature: ()V
 485  */
 486 JNIEXPORT void JNICALL
 487 Java_java_net_NetworkInterface_init(JNIEnv *env, jclass cls)
 488 {
 489     /*
 490      * Get the various JNI ids that we require
 491      */
 492     ni_class = (*env)->NewGlobalRef(env, cls);
 493     CHECK_NULL(ni_class);
 494     ni_nameID = (*env)->GetFieldID(env, ni_class, "name", "Ljava/lang/String;");
 495     CHECK_NULL(ni_nameID);
 496     ni_displayNameID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;");
 497     CHECK_NULL(ni_displayNameID);
 498     ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
 499     CHECK_NULL(ni_indexID);
 500     ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;");
 501     CHECK_NULL(ni_addrsID);
 502     ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;");
 503     CHECK_NULL(ni_bindsID);
 504     ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;");
 505     CHECK_NULL(ni_childsID);
 506     ni_ctor = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
 507     CHECK_NULL(ni_ctor);
 508     ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
 509     CHECK_NULL(ni_ibcls);
 510     ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
 511     CHECK_NULL(ni_ibcls);
 512     ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
 513     CHECK_NULL(ni_ibctrID);
 514     ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;");
 515     CHECK_NULL(ni_ibaddressID);
 516     ni_ibbroadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;");
 517     CHECK_NULL(ni_ibbroadcastID);
 518     ni_ibmaskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
 519     CHECK_NULL(ni_ibmaskID);
 520 
 521     initInetAddressIDs(env);
 522 }
 523 
 524 /*
 525  * Create a NetworkInterface object, populate the name and index, and
 526  * populate the InetAddress array based on the IP addresses for this
 527  * interface.
 528  */
 529 jobject createNetworkInterface
 530     (JNIEnv *env, netif *ifs, int netaddrCount, netaddr *netaddrP)
 531 {
 532     jobject netifObj;
 533     jobject name, displayName;
 534     jobjectArray addrArr, bindsArr, childArr;
 535     netaddr *addrs;
 536     jint addr_index;
 537     jint bind_index;
 538 
 539     /*
 540      * Create a NetworkInterface object and populate it
 541      */
 542     netifObj = (*env)->NewObject(env, ni_class, ni_ctor);
 543     CHECK_NULL_RETURN(netifObj, NULL);
 544     name = (*env)->NewStringUTF(env, ifs->name);
 545     CHECK_NULL_RETURN(name, NULL);
 546     if (ifs->dNameIsUnicode) {
 547         displayName = (*env)->NewString(env, (PWCHAR)ifs->displayName,
 548                                        (jsize)wcslen ((PWCHAR)ifs->displayName));
 549     } else {
 550         displayName = (*env)->NewStringUTF(env, ifs->displayName);
 551     }
 552     CHECK_NULL_RETURN(displayName, NULL);
 553     (*env)->SetObjectField(env, netifObj, ni_nameID, name);
 554     (*env)->SetObjectField(env, netifObj, ni_displayNameID, displayName);
 555     (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
 556 
 557     /*
 558      * Get the IP addresses for this interface if necessary
 559      * Note that 0 is a valid number of addresses.
 560      */
 561     if (netaddrCount < 0) {
 562         netaddrCount = enumAddresses_win(env, ifs, &netaddrP);
 563         if (netaddrCount < 0) {
 564             return NULL;
 565         }
 566     }
 567     addrArr = (*env)->NewObjectArray(env, netaddrCount, ia_class, NULL);
 568     if (addrArr == NULL) {
 569         free_netaddr(netaddrP);
 570         return NULL;
 571     }
 572 
 573     bindsArr = (*env)->NewObjectArray(env, netaddrCount, ni_ibcls, NULL);
 574     if (bindsArr == NULL) {
 575       free_netaddr(netaddrP);
 576       return NULL;
 577     }
 578     addrs = netaddrP;
 579     addr_index = 0;
 580     bind_index = 0;
 581     while (addrs != NULL) {
 582         jobject iaObj, ia2Obj;
 583         jobject ibObj = NULL;
 584         if (addrs->addr.sa.sa_family == AF_INET) {
 585             iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 586             if (iaObj == NULL) {
 587                 free_netaddr(netaddrP);
 588                 return NULL;
 589             }
 590             /* default ctor will set family to AF_INET */
 591 
 592             setInetAddress_addr(env, iaObj, ntohl(addrs->addr.sa4.sin_addr.s_addr));
 593             if ((*env)->ExceptionCheck(env)) {
 594                 free_netaddr(netaddrP);
 595                 return NULL;
 596             }
 597             if (addrs->mask != -1) {
 598               ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
 599               if (ibObj == NULL) {
 600                 free_netaddr(netaddrP);
 601                 return NULL;
 602               }
 603               (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
 604               ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
 605               if (ia2Obj == NULL) {
 606                 free_netaddr(netaddrP);
 607                 return NULL;
 608               }
 609               setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.sa4.sin_addr.s_addr));
 610               if ((*env)->ExceptionCheck(env)) {
 611                   free_netaddr(netaddrP);
 612                   return NULL;
 613               }
 614               (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj);
 615               (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
 616               (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
 617             }
 618         } else /* AF_INET6 */ {
 619             int scope;
 620             iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
 621             if (iaObj) {
 622                 jboolean ret = setInet6Address_ipaddress(env, iaObj,  (jbyte *)&(addrs->addr.sa6.sin6_addr.s6_addr));
 623                 if (ret == JNI_FALSE) {
 624                     free_netaddr(netaddrP);
 625                     return NULL;
 626                 }
 627 
 628                 scope = addrs->addr.sa6.sin6_scope_id;
 629                 if (scope != 0) { /* zero is default value, no need to set */
 630                     setInet6Address_scopeid(env, iaObj, scope);
 631                     setInet6Address_scopeifname(env, iaObj, netifObj);
 632                 }
 633                 ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
 634                 if (ibObj == NULL) {
 635                   free_netaddr(netaddrP);
 636                   return NULL;
 637                 }
 638                 (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
 639                 (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
 640                 (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
 641             }
 642         }
 643         (*env)->SetObjectArrayElement(env, addrArr, addr_index, iaObj);
 644         addrs = addrs->next;
 645         addr_index++;
 646     }
 647     (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
 648     (*env)->SetObjectField(env, netifObj, ni_bindsID, bindsArr);
 649 
 650     free_netaddr(netaddrP);
 651 
 652     /*
 653      * Windows doesn't have virtual interfaces, so child array
 654      * is always empty.
 655      */
 656     childArr = (*env)->NewObjectArray(env, 0, ni_class, NULL);
 657     if (childArr == NULL) {
 658       return NULL;
 659     }
 660     (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
 661 
 662     /* return the NetworkInterface */
 663     return netifObj;
 664 }
 665 
 666 /*
 667  * Class:     java_net_NetworkInterface
 668  * Method:    getByName0
 669  * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
 670  */
 671 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0
 672     (JNIEnv *env, jclass cls, jstring name)
 673 {
 674     netif *ifList, *curr;
 675     jboolean isCopy;
 676     const char *name_utf;
 677     jobject netifObj = NULL;
 678 
 679     // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 680     if (ipv6_available()) {
 681         return Java_java_net_NetworkInterface_getByName0_XP (env, cls, name);
 682     }
 683 
 684     /* get the list of interfaces */
 685     if (enumInterfaces(env, &ifList) < 0) {
 686         return NULL;
 687     }
 688 
 689     /* get the name as a C string */
 690     name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
 691     if (name_utf != NULL) {
 692 
 693         /* Search by name */
 694         curr = ifList;
 695         while (curr != NULL) {
 696             if (strcmp(name_utf, curr->name) == 0) {
 697                 break;
 698             }
 699             curr = curr->next;
 700         }
 701 
 702         /* if found create a NetworkInterface */
 703         if (curr != NULL) {;
 704             netifObj = createNetworkInterface(env, curr, -1, NULL);
 705         }
 706 
 707         /* release the UTF string */
 708         (*env)->ReleaseStringUTFChars(env, name, name_utf);
 709     } else {
 710         if (!(*env)->ExceptionCheck(env))
 711             JNU_ThrowOutOfMemoryError(env, NULL);
 712     }
 713 
 714     /* release the interface list */
 715     free_netif(ifList);
 716 
 717     return netifObj;
 718 }
 719 
 720 /*
 721  * Class:     NetworkInterface
 722  * Method:    getByIndex0
 723  * Signature: (I)LNetworkInterface;
 724  */
 725 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0
 726   (JNIEnv *env, jclass cls, jint index)
 727 {
 728     netif *ifList, *curr;
 729     jobject netifObj = NULL;
 730 
 731     // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 732     if (ipv6_available()) {
 733         return Java_java_net_NetworkInterface_getByIndex0_XP (env, cls, index);
 734     }
 735 
 736     /* get the list of interfaces */
 737     if (enumInterfaces(env, &ifList) < 0) {
 738         return NULL;
 739     }
 740 
 741     /* search by index */
 742     curr = ifList;
 743     while (curr != NULL) {
 744         if (index == curr->index) {
 745             break;
 746         }
 747         curr = curr->next;
 748     }
 749 
 750     /* if found create a NetworkInterface */
 751     if (curr != NULL) {
 752         netifObj = createNetworkInterface(env, curr, -1, NULL);
 753     }
 754 
 755     /* release the interface list */
 756     free_netif(ifList);
 757 
 758     return netifObj;
 759 }
 760 
 761 /*
 762  * Class:     java_net_NetworkInterface
 763  * Method:    getByInetAddress0
 764  * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
 765  */
 766 JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
 767     (JNIEnv *env, jclass cls, jobject iaObj)
 768 {
 769     netif *ifList, *curr;
 770     jobject netifObj = NULL;
 771     jint addr = getInetAddress_addr(env, iaObj);
 772     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
 773 
 774     // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 775     if (ipv6_available()) {
 776         return Java_java_net_NetworkInterface_getByInetAddress0_XP (env, cls, iaObj);
 777     }
 778 
 779     /* get the list of interfaces */
 780     if (enumInterfaces(env, &ifList) < 0) {
 781         return NULL;
 782     }
 783 
 784     /*
 785      * Enumerate the addresses on each interface until we find a
 786      * matching address.
 787      */
 788     curr = ifList;
 789     while (curr != NULL) {
 790         int count;
 791         netaddr *addrList;
 792         netaddr *addrP;
 793 
 794         /* enumerate the addresses on this interface */
 795         count = enumAddresses_win(env, curr, &addrList);
 796         if (count < 0) {
 797             free_netif(ifList);
 798             return NULL;
 799         }
 800 
 801         /* iterate through each address */
 802         addrP = addrList;
 803 
 804         while (addrP != NULL) {
 805             if ((unsigned long)addr == ntohl(addrP->addr.sa4.sin_addr.s_addr)) {
 806                 break;
 807             }
 808             addrP = addrP->next;
 809         }
 810 
 811         /*
 812          * Address matched so create NetworkInterface for this interface
 813          * and address list.
 814          */
 815         if (addrP != NULL) {
 816             /* createNetworkInterface will free addrList */
 817             netifObj = createNetworkInterface(env, curr, count, addrList);
 818             break;
 819         }
 820 
 821         /* on next interface */
 822         curr = curr->next;
 823     }
 824 
 825     /* release the interface list */
 826     free_netif(ifList);
 827 
 828     return netifObj;
 829 }
 830 
 831 /*
 832  * Class:     java_net_NetworkInterface
 833  * Method:    getAll
 834  * Signature: ()[Ljava/net/NetworkInterface;
 835  */
 836 JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll
 837     (JNIEnv *env, jclass cls)
 838 {
 839     int count;
 840     netif *ifList = NULL, *curr;
 841     jobjectArray netIFArr;
 842     jint arr_index;
 843 
 844     // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 845     if (ipv6_available()) {
 846         return Java_java_net_NetworkInterface_getAll_XP (env, cls);
 847     }
 848 
 849     /*
 850      * Get list of interfaces
 851      */
 852     count = enumInterfaces(env, &ifList);
 853     if (count < 0) {
 854         return NULL;
 855     }
 856 
 857     /* allocate a NetworkInterface array */
 858     netIFArr = (*env)->NewObjectArray(env, count, cls, NULL);
 859     if (netIFArr == NULL) {
 860         free_netif(ifList);
 861         return NULL;
 862     }
 863 
 864     /*
 865      * Iterate through the interfaces, create a NetworkInterface instance
 866      * for each array element and populate the object.
 867      */
 868     curr = ifList;
 869     arr_index = 0;
 870     while (curr != NULL) {
 871         jobject netifObj;
 872 
 873         netifObj = createNetworkInterface(env, curr, -1, NULL);
 874         if (netifObj == NULL) {
 875             free_netif(ifList);
 876             return NULL;
 877         }
 878 
 879         /* put the NetworkInterface into the array */
 880         (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
 881 
 882         curr = curr->next;
 883     }
 884 
 885     /* release the interface list */
 886     free_netif(ifList);
 887 
 888     return netIFArr;
 889 }
 890 
 891 /*
 892  * Class:     java_net_NetworkInterface
 893  * Method:    isUp0
 894  * Signature: (Ljava/lang/String;)Z
 895  */
 896 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0
 897     (JNIEnv *env, jclass cls, jstring name, jint index) {
 898   jboolean ret = JNI_FALSE;
 899 
 900   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 901   if (ipv6_available()) {
 902     return Java_java_net_NetworkInterface_isUp0_XP(env, cls, name, index);
 903   } else {
 904     MIB_IFROW *ifRowP;
 905     ifRowP = getIF(index);
 906     if (ifRowP != NULL) {
 907       ret = ifRowP->dwAdminStatus == MIB_IF_ADMIN_STATUS_UP &&
 908             (ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL ||
 909              ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED);
 910       free(ifRowP);
 911     }
 912   }
 913     return ret;
 914 }
 915 
 916 /*
 917  * Class:     java_net_NetworkInterface
 918  * Method:    isP2P0
 919  * Signature: (Ljava/lang/String;I)Z
 920  */
 921 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0
 922     (JNIEnv *env, jclass cls, jstring name, jint index) {
 923   MIB_IFROW *ifRowP;
 924   jboolean ret = JNI_FALSE;
 925 
 926   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 927   if (ipv6_available()) {
 928     return Java_java_net_NetworkInterface_isP2P0_XP(env, cls, name, index);
 929   } else {
 930     ifRowP = getIF(index);
 931     if (ifRowP != NULL) {
 932       switch(ifRowP->dwType) {
 933       case MIB_IF_TYPE_PPP:
 934       case MIB_IF_TYPE_SLIP:
 935         ret = JNI_TRUE;
 936         break;
 937       }
 938       free(ifRowP);
 939     }
 940   }
 941   return ret;
 942 }
 943 
 944 /*
 945  * Class:     java_net_NetworkInterface
 946  * Method:    isLoopback0
 947  * Signature: (Ljava/lang/String;I)Z
 948  */
 949 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0
 950     (JNIEnv *env, jclass cls, jstring name, jint index) {
 951   MIB_IFROW *ifRowP;
 952   jboolean ret = JNI_FALSE;
 953 
 954   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 955   if (ipv6_available()) {
 956     return Java_java_net_NetworkInterface_isLoopback0_XP(env, cls, name, index);
 957   } else {
 958     ifRowP = getIF(index);
 959     if (ifRowP != NULL) {
 960       if (ifRowP->dwType == MIB_IF_TYPE_LOOPBACK)
 961         ret = JNI_TRUE;
 962       free(ifRowP);
 963     }
 964     return ret;
 965   }
 966 }
 967 
 968 /*
 969  * Class:     java_net_NetworkInterface
 970  * Method:    supportsMulticast0
 971  * Signature: (Ljava/lang/String;I)Z
 972  */
 973 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0
 974     (JNIEnv *env, jclass cls, jstring name, jint index) {
 975     return Java_java_net_NetworkInterface_supportsMulticast0_XP(env, cls,
 976                                                                name, index);
 977 }
 978 
 979 /*
 980  * Class:     java_net_NetworkInterface
 981  * Method:    getMacAddr0
 982  * Signature: ([bLjava/lang/String;I)[b
 983  */
 984 JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0
 985     (JNIEnv *env, jclass class, jbyteArray addrArray, jstring name, jint index) {
 986   jbyteArray ret = NULL;
 987   int len;
 988   MIB_IFROW *ifRowP;
 989 
 990   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
 991   if (ipv6_available()) {
 992     return Java_java_net_NetworkInterface_getMacAddr0_XP(env, class, name, index);
 993   } else {
 994     ifRowP = getIF(index);
 995     if (ifRowP != NULL) {
 996       switch(ifRowP->dwType) {
 997       case MIB_IF_TYPE_ETHERNET:
 998       case MIB_IF_TYPE_TOKENRING:
 999       case MIB_IF_TYPE_FDDI:
1000       case IF_TYPE_IEEE80211:
1001         len = ifRowP->dwPhysAddrLen;
1002         if (len > 0) {
1003             ret = (*env)->NewByteArray(env, len);
1004             if (!IS_NULL(ret)) {
1005               (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) ifRowP->bPhysAddr);
1006             }
1007         }
1008         break;
1009       }
1010       free(ifRowP);
1011     }
1012     return ret;
1013   }
1014 }
1015 
1016 /*
1017  * Class:       java_net_NetworkInterface
1018  * Method:      getMTU0
1019  * Signature:   ([bLjava/lang/String;I)I
1020  */
1021 JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0
1022     (JNIEnv *env, jclass class, jstring name, jint index) {
1023   jint ret = -1;
1024   MIB_IFROW *ifRowP;
1025 
1026   // Retained for now to support IPv4 only stack, java.net.preferIPv4Stack
1027   if (ipv6_available()) {
1028     return Java_java_net_NetworkInterface_getMTU0_XP(env, class, name, index);
1029   } else {
1030     ifRowP = getIF(index);
1031     if (ifRowP != NULL) {
1032       ret = ifRowP->dwMtu;
1033       free(ifRowP);
1034     }
1035     return ret;
1036   }
1037 }