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