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