1/*
2 * Copyright (c) 2003, 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
36extern int enumAddresses_win(JNIEnv *env, netif *netifP, netaddr **netaddrPP);
37int getAddrsFromAdapter(IP_ADAPTER_ADDRESSES *ptr, netaddr **netaddrPP);
38
39#ifdef DEBUG
40void printnif (netif *nif) {
41#ifdef _WIN64
42        printf ("nif:0x%I64x name:%s\n", nif,nif->name);
43#else
44        printf ("nif:0x%x name:%s\n", nif,nif->name);
45#endif
46        if (nif->dNameIsUnicode) {
47            printf ("dName:%S index:%d ", nif->displayName,nif->index);
48        } else {
49            printf ("dName:%s index:%d ", nif->displayName,nif->index);
50        }
51        printf ("naddrs:%d\n", nif->naddrs);
52}
53
54void printnifs (netif *netifPP, char *str) {
55    netif *nif;
56    printf ("%s\n", str);
57    for (nif=netifPP; nif!=NULL; nif=nif->next) {
58        printnif (nif);
59    }
60    printf("-----------------\n");
61}
62
63#endif
64
65static int bufsize = 4096;
66
67/*
68 * return an array of IP_ADAPTER_ADDRESSES containing one element
69 * for each adapter on the system. Returned in *adapters.
70 * Buffer is malloc'd and must be freed (unless error returned)
71 */
72static int getAdapters (JNIEnv *env, IP_ADAPTER_ADDRESSES **adapters) {
73    DWORD ret, flags;
74    IP_ADAPTER_ADDRESSES *adapterInfo;
75    ULONG len;
76    char *error_msg_buf = NULL;
77    size_t error_msg_buf_size =
78            strlen("IP Helper Library GetAdaptersAddresses function failed"
79                   " with error == ") + 10;
80    int _ret = 0;
81
82
83    adapterInfo = (IP_ADAPTER_ADDRESSES *)malloc (bufsize);
84    if (adapterInfo == NULL) {
85        JNU_ThrowByName(env, "java/lang/OutOfMemoryError",
86            "Native heap allocation failure");
87        return -1;
88    }
89
90    len = bufsize;
91    flags = GAA_FLAG_SKIP_DNS_SERVER;
92    flags |= GAA_FLAG_SKIP_MULTICAST;
93    flags |= GAA_FLAG_INCLUDE_PREFIX;
94    ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo, &len);
95
96    if (ret == ERROR_BUFFER_OVERFLOW) {
97        IP_ADAPTER_ADDRESSES * newAdapterInfo = NULL;
98        if (len  < (ULONG_MAX - bufsize)) {
99            len = len + bufsize;
100        }
101        newAdapterInfo =
102            (IP_ADAPTER_ADDRESSES *) realloc (adapterInfo, len);
103        if (newAdapterInfo == NULL) {
104            free(adapterInfo);
105            JNU_ThrowByName(env, "java/lang/OutOfMemoryError",
106                "Native heap allocation failure");
107            return -1;
108        }
109
110        adapterInfo = newAdapterInfo;
111
112        ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo, &len);
113    }
114
115    if (ret != ERROR_SUCCESS) {
116        free (adapterInfo);
117        if (ret == ERROR_INSUFFICIENT_BUFFER) {
118            JNU_ThrowByName(env, "java/lang/Error",
119                "IP Helper Library GetAdaptersAddresses function failed "
120                "with ERROR_INSUFFICIENT_BUFFER");
121        } else if (ret == ERROR_ADDRESS_NOT_ASSOCIATED ) {
122            JNU_ThrowByName(env, "java/lang/Error",
123                "IP Helper Library GetAdaptersAddresses function failed "
124                "with ERROR_ADDRESS_NOT_ASSOCIATED");
125        } else {
126            error_msg_buf = (char *)malloc(error_msg_buf_size);
127            if (error_msg_buf != NULL) {
128                memset(error_msg_buf, 0, error_msg_buf_size);
129                _ret = _snprintf_s(error_msg_buf, error_msg_buf_size,
130                    _TRUNCATE, "IP Helper Library GetAdaptersAddresses "
131                                "function failed with error == %d", ret);
132                if (_ret != -1) {
133                    JNU_ThrowByName(env, "java/lang/Error", error_msg_buf);
134                } else {
135                    JNU_ThrowByName(env, "java/lang/Error",
136                        "IP Helper Library GetAdaptersAddresses function failure");
137                }
138            } else {
139                JNU_ThrowByName(env, "java/lang/Error",
140                    "IP Helper Library GetAdaptersAddresses function failed");
141            }
142        }
143        return -1;
144    }
145    *adapters = adapterInfo;
146    return ERROR_SUCCESS;
147}
148
149/*
150 * return an array of IP_ADAPTER_ADDRESSES containing one element
151 * for each adapter on the system. Returned in *adapters.
152 * Buffer is malloc'd and must be freed (unless error returned)
153 */
154IP_ADAPTER_ADDRESSES *getAdapter (JNIEnv *env,  jint index) {
155    DWORD flags, val;
156    IP_ADAPTER_ADDRESSES *adapterInfo, *ptr, *ret;
157    ULONG len;
158    char *error_msg_buf = NULL;
159    size_t error_msg_buf_size =
160        strlen("IP Helper Library GetAdaptersAddresses function failed with error == ") + 10;
161    int _ret = 0;
162    adapterInfo = (IP_ADAPTER_ADDRESSES *)malloc (bufsize);
163    if (adapterInfo == NULL) {
164        JNU_ThrowByName(env, "java/lang/OutOfMemoryError",
165            "Native heap allocation failure");
166        return NULL;
167    }
168    len = bufsize;
169    flags = GAA_FLAG_SKIP_DNS_SERVER;
170    flags |= GAA_FLAG_SKIP_MULTICAST;
171    flags |= GAA_FLAG_INCLUDE_PREFIX;
172    val = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo, &len);
173    if (val == ERROR_BUFFER_OVERFLOW) {
174        IP_ADAPTER_ADDRESSES * newAdapterInfo = NULL;
175        if (len  < (ULONG_MAX - bufsize)) {
176            len = len + bufsize;
177        }
178        newAdapterInfo =
179                (IP_ADAPTER_ADDRESSES *) realloc (adapterInfo, len);
180        if (newAdapterInfo == NULL) {
181            free(adapterInfo);
182            JNU_ThrowByName(env, "java/lang/OutOfMemoryError",
183                "Native heap allocation failure");
184            return NULL;
185        }
186
187        adapterInfo = newAdapterInfo;
188
189        val = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapterInfo, &len);
190    }
191
192    if (val != ERROR_SUCCESS) {
193        free (adapterInfo);
194        if (val == ERROR_INSUFFICIENT_BUFFER) {
195            JNU_ThrowByName(env, "java/lang/Error",
196                "IP Helper Library GetAdaptersAddresses function failed "
197                "with ERROR_INSUFFICIENT_BUFFER");
198        } else if (val == ERROR_ADDRESS_NOT_ASSOCIATED ) {
199            JNU_ThrowByName(env, "java/lang/Error",
200                "IP Helper Library GetAdaptersAddresses function failed "
201                "with ERROR_ADDRESS_NOT_ASSOCIATED");
202        } else {
203            error_msg_buf = (char *)malloc(error_msg_buf_size);
204            if (error_msg_buf != NULL) {
205                memset(error_msg_buf, 0, error_msg_buf_size);
206                _ret = _snprintf_s(error_msg_buf, error_msg_buf_size,
207                    _TRUNCATE, "IP Helper Library GetAdaptersAddresses function failed "
208                               "with error == %d", val);
209                if (_ret != -1) {
210                    JNU_ThrowByName(env, "java/lang/Error", error_msg_buf);
211                } else {
212                    JNU_ThrowByName(env, "java/lang/Error",
213                        "IP Helper Library GetAdaptersAddresses function failure");
214                }
215            } else {
216                JNU_ThrowByName(env, "java/lang/Error",
217                    "IP Helper Library GetAdaptersAddresses function failed");
218            }
219        }
220        return NULL;
221    }
222
223    ptr = adapterInfo;
224    ret = NULL;
225    while (ptr != NULL) {
226      // in theory the IPv4 index and the IPv6 index can be the same
227      // where an interface is enabled for v4 and v6
228      // IfIndex == 0 IPv4 not available on this interface
229      // Ipv6IfIndex == 0 IPv6 not available on this interface
230      if (((ptr->IfIndex != 0)&&(ptr->IfIndex == index)) ||
231          ((ptr->Ipv6IfIndex !=0) && (ptr->Ipv6IfIndex == index))) {
232        ret = (IP_ADAPTER_ADDRESSES *) malloc(sizeof(IP_ADAPTER_ADDRESSES));
233        if (ret == NULL) {
234            free(adapterInfo);
235            JNU_ThrowByName(env, "java/lang/OutOfMemoryError",
236                "Native heap allocation failure");
237            return NULL;
238        }
239
240        //copy the memory and break out of the while loop.
241        memcpy(ret, ptr, sizeof(IP_ADAPTER_ADDRESSES));
242        break;
243
244      }
245      ptr=ptr->Next;
246    }
247    free(adapterInfo);
248    return ret;
249}
250
251static int ipinflen = 2048;
252
253/*
254 */
255int getAllInterfacesAndAddresses (JNIEnv *env, netif **netifPP)
256{
257    DWORD ret;
258    IP_ADAPTER_ADDRESSES *ptr, *adapters=NULL;
259    ULONG len=ipinflen, count=0;
260    netif *nif=NULL, *dup_nif, *last=NULL, *loopif=NULL, *curr;
261    int tun=0, net=0;
262
263    *netifPP = NULL;
264   /*
265    * Get the IPv4 interfaces. This information is the same
266    * as what previous JDK versions would return.
267    */
268
269    ret = enumInterfaces(env, netifPP);
270    if (ret == -1) {
271        return -1;
272    } else {
273        count = ret;
274    }
275
276    /* locate the loopback (and the last) interface */
277    for (nif=*netifPP, last=nif; nif!=NULL; nif=nif->next) {
278        if (nif->ifType == MIB_IF_TYPE_LOOPBACK) {
279            loopif = nif;
280        }
281        last = nif;
282    }
283
284    // Retrieve IPv4 addresses with the IP Helper API
285    curr = *netifPP;
286    while (curr != NULL) {
287        netaddr *netaddrP;
288        ret = enumAddresses_win(env, curr, &netaddrP);
289        if (ret == -1) {
290            return -1;
291        }
292        curr->addrs = netaddrP;
293        curr->naddrs += ret;
294        curr = curr->next;
295    }
296
297    ret = getAdapters (env, &adapters);
298    if (ret != ERROR_SUCCESS) {
299        goto err;
300    }
301
302    /* Now get the IPv6 information. This includes:
303     *  (a)  IPv6 information associated with interfaces already found
304     *  (b)  IPv6 information for IPv6 only interfaces (probably tunnels)
305     *
306     * For compatibility with previous releases we use the naming
307     * information gotten from enumInterfaces() for (a) entries
308     * However, the index numbers are taken from the new API.
309     *
310     * The procedure is to go through the list of adapters returned
311     * by the new API looking for entries that correspond to IPv4 interfaces
312     * already found.
313     */
314
315    ptr = adapters;
316    while (ptr != NULL) {
317        int c;
318        netif *nif0;
319        if (ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK && (loopif != NULL)) {
320            c = getAddrsFromAdapter(ptr, &loopif->addrs);
321            if (c == -1) {
322                goto err;
323            }
324            loopif->naddrs += c;
325        } else {
326            int index = ptr->IfIndex;
327            if (index != 0) {
328                /* This entry is associated with an IPv4 interface */
329                for (nif=*netifPP; nif!=NULL; nif=nif->next) {
330                    if (nif->index == index) {
331                        /* found the interface entry
332                         * set the index to the IPv6 index and add the
333                         * IPv6 addresses
334                         */
335                        nif->ipv6Index = ptr->Ipv6IfIndex;
336                        c = getAddrsFromAdapter(ptr, &nif->addrs);
337                        nif->naddrs += c;
338                        break;
339                    }
340                }
341            } else {
342                /* This entry is IPv6 only */
343                char newname [128];
344                int c;
345
346                /* Windows allocates duplicate adapter entries
347                 * for tunnel interfaces when there are multiple
348                 * physical adapters. Need to check
349                 * if this is a duplicate (ipv6Index is the same)
350                 */
351                dup_nif = 0;
352                for (nif0=*netifPP; nif0!=NULL; nif0=nif0->next) {
353                    if (nif0->hasIpv6Address &&
354                                ptr->Ipv6IfIndex == nif0->ipv6Index) {
355                        dup_nif = nif0;
356                        break;
357                    }
358                }
359                if (dup_nif == 0) {
360                    /* new interface */
361                        nif = (netif *) calloc (1, sizeof(netif));
362                        if (nif == 0) {
363                            goto err;
364                        }
365                        if (ptr->IfType == IF_TYPE_TUNNEL) {
366                                sprintf (newname, "tun%d", tun);
367                                tun ++;
368                        } else {
369                                sprintf (newname, "net%d", net);
370                                net ++;
371                        }
372                        nif->name = malloc (strlen(newname)+1);
373                        nif->displayName = malloc (wcslen(ptr->FriendlyName)*2+2);
374                        if (nif->name == 0 || nif->displayName == 0) {
375                                goto err;
376                        }
377                        strcpy (nif->name, newname);
378                        wcscpy ((PWCHAR)nif->displayName, ptr->FriendlyName);
379                        nif->dNameIsUnicode = TRUE;
380
381                        // the java.net.NetworkInterface abstraction only has index
382                        // so the Ipv6IfIndex needs to map onto index
383                        nif->index = ptr->Ipv6IfIndex;
384                        nif->ipv6Index = ptr->Ipv6IfIndex;
385                        nif->hasIpv6Address = TRUE;
386
387                        last->next = nif;
388                        last = nif;
389                        count++;
390                        c = getAddrsFromAdapter(ptr, &nif->addrs);
391                        if (c == -1) {
392                                goto err;
393                        }
394                        nif->naddrs += c;
395                 } else {
396                        /* add the addresses from this adapter to the
397                         * original (dup_nif)
398                         */
399                        c = getAddrsFromAdapter(ptr, &dup_nif->addrs);
400                        if (c == -1) {
401                                goto err;
402                        }
403                        dup_nif->naddrs += c;
404                }
405            }
406        }
407        ptr=ptr->Next;
408    }
409
410    free (adapters);
411    return count;
412
413err:
414    if (*netifPP) {
415        free_netif (*netifPP);
416    }
417    if (adapters) {
418        free (adapters);
419    }
420    return -1;
421}
422
423/* If *netaddrPP is null, then the addresses are allocated and the beginning
424 * of the allocated chain is returned in *netaddrPP.
425 * If *netaddrPP is not null, then the addresses allocated here are appended
426 * to the existing chain.
427 *
428 * Returns count of addresses or -1 on error.
429 */
430
431static int getAddrsFromAdapter(IP_ADAPTER_ADDRESSES *ptr, netaddr **netaddrPP) {
432        LPSOCKADDR sock;
433        int        count = 0;
434        netaddr    *curr, *start = NULL, *prev = NULL;
435        PIP_ADAPTER_UNICAST_ADDRESS uni_addr;
436        PIP_ADAPTER_ANYCAST_ADDRESS any_addr;
437        PIP_ADAPTER_PREFIX prefix;
438
439        /* If chain passed in, find end */
440        if (*netaddrPP != NULL) {
441            for (start=*netaddrPP; start->next!=NULL; start=start->next)
442                ;
443
444            prev=start;
445        }
446
447        prefix = ptr->FirstPrefix;
448        /* Unicast */
449        uni_addr = ptr->FirstUnicastAddress;
450        while (uni_addr != NULL) {
451        /* address is only usable if dad state is preferred or deprecated */
452                if (uni_addr->DadState == IpDadStateDeprecated ||
453                                uni_addr->DadState == IpDadStatePreferred) {
454                        sock = uni_addr->Address.lpSockaddr;
455
456                        // IPv4 addresses already retrieved with enumAddresses_win
457                        if (sock->sa_family == AF_INET) {
458                                uni_addr = uni_addr->Next;
459                                continue;
460                        }
461
462            curr = (netaddr *)calloc (1, sizeof (netaddr));
463
464            if (curr == NULL)
465                goto freeAllocatedMemory;
466
467            if (start == NULL)
468                start = curr;
469
470            if (prev != NULL)
471               prev->next = curr;
472
473            prev = curr;
474            SOCKETADDRESS_COPY (&curr->addr, sock);
475            if (prefix != NULL) {
476              curr->mask = (short)prefix->PrefixLength;
477              prefix = prefix->Next;
478            }
479            count ++;
480        }
481        uni_addr = uni_addr->Next;
482    }
483    /* Anycast */
484    any_addr = ptr->FirstAnycastAddress;
485    while (any_addr != NULL) {
486        curr = (netaddr *)calloc (1, sizeof (netaddr));
487
488        if (curr == NULL)
489            goto freeAllocatedMemory;
490
491        if (start == NULL)
492            start = curr;
493
494        if (prev != NULL)
495            prev->next = curr;
496
497        prev = curr;
498        sock = any_addr->Address.lpSockaddr;
499        SOCKETADDRESS_COPY (&curr->addr, sock);
500        count ++;
501        any_addr = any_addr->Next;
502    }
503    if (*netaddrPP == NULL) {
504        *netaddrPP = start;
505    }
506    return count;
507
508freeAllocatedMemory:
509
510    if (*netaddrPP != NULL) {
511        //N.B. the variable "start" cannot be NULL at this point because we started with an
512        //existing list.
513        curr=start->next;
514        start->next = NULL;
515        start = curr;
516    }
517    // otherwise, "start" points to the beginning of an incomplete list that we must deallocate.
518
519    while (start != NULL) {
520        curr = start->next;
521        free(start);
522        start = curr;
523    }
524
525    return -1;
526}
527
528/*
529 * Create a NetworkInterface object, populate the name and index, and
530 * populate the InetAddress array based on the IP addresses for this
531 * interface.
532 */
533static jobject createNetworkInterfaceXP(JNIEnv *env, netif *ifs)
534{
535    jobject netifObj;
536    jobject name, displayName;
537    jobjectArray addrArr, bindsArr, childArr;
538    netaddr *addrs;
539    jint addr_index;
540    int netaddrCount=ifs->naddrs;
541    netaddr *netaddrP=ifs->addrs;
542    jint bind_index;
543
544    /*
545     * Create a NetworkInterface object and populate it
546     */
547    netifObj = (*env)->NewObject(env, ni_class, ni_ctor);
548    if (netifObj == NULL) {
549        return NULL;
550    }
551    name = (*env)->NewStringUTF(env, ifs->name);
552    if (name == NULL) {
553        return NULL;
554    }
555    if (ifs->dNameIsUnicode) {
556        displayName = (*env)->NewString(env, (PWCHAR)ifs->displayName,
557                                        (jsize)wcslen ((PWCHAR)ifs->displayName));
558    } else {
559        displayName = (*env)->NewStringUTF(env, ifs->displayName);
560    }
561    if (displayName == NULL) {
562        return NULL;
563    }
564    (*env)->SetObjectField(env, netifObj, ni_nameID, name);
565    (*env)->SetObjectField(env, netifObj, ni_displayNameID, displayName);
566    (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
567    /*
568     * Get the IP addresses for this interface if necessary
569     * Note that 0 is a valid number of addresses.
570     */
571    if (netaddrCount < 0) {
572        netaddrCount = enumAddresses_win(env, ifs, &netaddrP);
573        if (netaddrCount == -1) {
574            return NULL;
575        }
576    }
577
578    addrArr = (*env)->NewObjectArray(env, netaddrCount, ia_class, NULL);
579    if (addrArr == NULL) {
580        return NULL;
581    }
582
583    bindsArr = (*env)->NewObjectArray(env, netaddrCount, ni_ibcls, NULL);
584    if (bindsArr == NULL) {
585      free_netaddr(netaddrP);
586      return NULL;
587    }
588
589    addrs = netaddrP;
590    addr_index = 0;
591    bind_index = 0;
592    while (addrs != NULL) {
593        jobject iaObj, ia2Obj;
594        jobject ibObj = NULL;
595        if (addrs->addr.sa.sa_family == AF_INET) {
596            iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
597            if (iaObj == NULL) {
598                return NULL;
599            }
600            /* default ctor will set family to AF_INET */
601
602            setInetAddress_addr(env, iaObj, ntohl(addrs->addr.sa4.sin_addr.s_addr));
603
604            ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
605            if (ibObj == NULL) {
606              free_netaddr(netaddrP);
607              return NULL;
608            }
609            (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
610            ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
611            if (ia2Obj == NULL) {
612              free_netaddr(netaddrP);
613              return NULL;
614            }
615            setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.sa4.sin_addr.s_addr));
616            (*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj);
617            (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
618            (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
619        } else /* AF_INET6 */ {
620            int scope;
621            jboolean ret;
622            iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
623            if (iaObj == NULL) {
624                return NULL;
625            }
626            ret = setInet6Address_ipaddress(env, iaObj, (jbyte *)&(addrs->addr.sa6.sin6_addr.s6_addr));
627            if (ret == JNI_FALSE) {
628                return NULL;
629            }
630            scope = addrs->addr.sa6.sin6_scope_id;
631            if (scope != 0) { /* zero is default value, no need to set */
632                setInet6Address_scopeid(env, iaObj, scope);
633                setInet6Address_scopeifname(env, iaObj, netifObj);
634            }
635            ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
636            if (ibObj == NULL) {
637              free_netaddr(netaddrP);
638              return NULL;
639            }
640            (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
641            (*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
642            (*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
643        }
644        (*env)->SetObjectArrayElement(env, addrArr, addr_index, iaObj);
645        addrs = addrs->next;
646        addr_index++;
647    }
648    (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
649    (*env)->SetObjectField(env, netifObj, ni_bindsID, bindsArr);
650
651    /*
652     * Windows doesn't have virtual interfaces, so child array
653     * is always empty.
654     */
655    childArr = (*env)->NewObjectArray(env, 0, ni_class, NULL);
656    if (childArr == NULL) {
657      return NULL;
658    }
659    (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
660
661    /* return the NetworkInterface */
662    return netifObj;
663}
664
665JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0_XP
666    (JNIEnv *env, jclass cls, jstring name)
667{
668    netif *ifList, *curr;
669    jboolean isCopy;
670    const char *name_utf;
671    jobject netifObj = NULL;
672
673    if (getAllInterfacesAndAddresses (env, &ifList) < 0) {
674        return NULL;
675    }
676
677    /* get the name as a C string */
678    name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
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 = createNetworkInterfaceXP(env, curr);
692    }
693
694    /* release the UTF string */
695    (*env)->ReleaseStringUTFChars(env, name, name_utf);
696
697    /* release the interface list */
698    free_netif(ifList);
699
700    return netifObj;
701}
702
703/*
704 * Class:     NetworkInterface
705 * Method:    getByIndex0_XP
706 * Signature: (I)LNetworkInterface;
707 */
708JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0_XP
709  (JNIEnv *env, jclass cls, jint index)
710{
711    netif *ifList, *curr;
712    jobject netifObj = NULL;
713
714    if (getAllInterfacesAndAddresses (env, &ifList) < 0) {
715        return NULL;
716    }
717
718    /* search by index */
719    curr = ifList;
720    while (curr != NULL) {
721        if (index == curr->index) {
722            break;
723        }
724        curr = curr->next;
725    }
726
727    /* if found create a NetworkInterface */
728    if (curr != NULL) {
729        netifObj = createNetworkInterfaceXP(env, curr);
730    }
731
732    /* release the interface list */
733    free_netif(ifList);
734
735    return netifObj;
736}
737
738/*
739 * Class:     java_net_NetworkInterface
740 * Method:    getByInetAddress0
741 * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
742 */
743JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0_XP
744    (JNIEnv *env, jclass cls, jobject iaObj)
745{
746    netif *ifList, *curr;
747    jobject netifObj = NULL;
748
749    /* get the list of interfaces */
750    if (getAllInterfacesAndAddresses (env, &ifList) < 0) {
751        return NULL;
752    }
753
754    /*
755     * Enumerate the addresses on each interface until we find a
756     * matching address.
757     */
758    curr = ifList;
759    while (curr != NULL) {
760        netaddr *addrList = curr->addrs;
761        netaddr *addrP;
762
763        /* iterate through each address */
764        addrP = addrList;
765
766        while (addrP != NULL) {
767            if (NET_SockaddrEqualsInetAddress(env,
768                                (struct sockaddr*)&addrP->addr, iaObj)) {
769                break;
770            }
771            addrP = addrP->next;
772        }
773
774        /*
775         * Address matched so create NetworkInterface for this interface
776         * and address list.
777         */
778        if (addrP != NULL) {
779            netifObj = createNetworkInterfaceXP(env, curr);
780            break;
781        }
782
783        /* on next interface */
784        curr = curr->next;
785    }
786
787    /* release the interface list */
788    free_netif(ifList);
789
790    return netifObj;
791}
792
793/*
794 * Class:     java_net_NetworkInterface
795 * Method:    getAll
796 * Signature: ()[Ljava/net/NetworkInterface;
797 */
798JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll_XP
799    (JNIEnv *env, jclass cls)
800{
801    int count;
802    netif *ifList, *curr;
803    jobjectArray netIFArr;
804    jint arr_index;
805
806    /*
807     * Get list of interfaces
808     */
809    count = getAllInterfacesAndAddresses (env, &ifList);
810    if (count < 0) {
811        return NULL;
812    }
813
814    /* allocate a NetworkInterface array */
815    netIFArr = (*env)->NewObjectArray(env, count, cls, NULL);
816    if (netIFArr == NULL) {
817        return NULL;
818    }
819
820    /*
821     * Iterate through the interfaces, create a NetworkInterface instance
822     * for each array element and populate the object.
823     */
824    curr = ifList;
825    arr_index = 0;
826    while (curr != NULL) {
827        jobject netifObj;
828
829        netifObj = createNetworkInterfaceXP(env, curr);
830        if (netifObj == NULL) {
831            return NULL;
832        }
833
834        /* put the NetworkInterface into the array */
835        (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
836        curr = curr->next;
837    }
838
839    /* release the interface list */
840    free_netif(ifList);
841
842    return netIFArr;
843}
844
845/*
846 * Class:     java_net_NetworkInterface
847 * Method:    supportsMulticast0
848 * Signature: (Ljava/lang/String;I)Z
849 */
850JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0_XP
851    (JNIEnv *env, jclass cls, jstring name, jint index) {
852      IP_ADAPTER_ADDRESSES *ptr;
853      jboolean val = JNI_TRUE;
854
855      ptr = getAdapter(env, index);
856      if (ptr != NULL) {
857        val = ptr->Flags & IP_ADAPTER_NO_MULTICAST ? JNI_FALSE : JNI_TRUE;
858        free(ptr);
859      }
860      return val;
861}
862
863/*
864 * Class:     java_net_NetworkInterface
865 * Method:    isUp0
866 * Signature: (Ljava/lang/String;I)Z
867 */
868JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0_XP
869    (JNIEnv *env, jclass cls, jstring name, jint index) {
870      IP_ADAPTER_ADDRESSES *ptr;
871      jboolean val = JNI_FALSE;
872
873      ptr = getAdapter(env, index);
874      if (ptr != NULL) {
875        val = ptr->OperStatus == IfOperStatusUp ? JNI_TRUE : JNI_FALSE;
876        free(ptr);
877      }
878      return val;
879}
880
881/*
882 * Class:     java_net_NetworkInterface
883 * Method:    getMacAddr0
884 * Signature: (Ljava/lang/String;I)Z
885 */
886JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0_XP
887    (JNIEnv *env, jclass cls, jstring name, jint index) {
888      IP_ADAPTER_ADDRESSES *ptr;
889      jbyteArray ret = NULL;
890      int len;
891
892      ptr = getAdapter(env, index);
893      if (ptr != NULL) {
894        len = ptr->PhysicalAddressLength;
895        if (len > 0) {
896          ret = (*env)->NewByteArray(env, len);
897          if (!IS_NULL(ret)) {
898            (*env)->SetByteArrayRegion(env, ret, 0, len,
899                                       (jbyte*) ptr->PhysicalAddress);
900          }
901        }
902        free(ptr);
903      }
904      return ret;
905}
906
907/*
908 * Class:       java_net_NetworkInterface
909 * Method:      getMTU0
910 * Signature:   ([bLjava/lang/String;I)I
911 */
912JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0_XP
913    (JNIEnv *env, jclass cls, jstring name, jint index) {
914      IP_ADAPTER_ADDRESSES *ptr;
915      jint ret = -1;
916
917      ptr = getAdapter(env, index);
918      if (ptr != NULL) {
919        ret = ptr->Mtu;
920        free(ptr);
921      }
922      return ret;
923}
924
925/*
926 * Class:     java_net_NetworkInterface
927 * Method:    isLoopback0
928 * Signature: (Ljava/lang/String;I)Z
929 */
930JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0_XP
931    (JNIEnv *env, jclass cls, jstring name, jint index) {
932      IP_ADAPTER_ADDRESSES *ptr;
933      jboolean val = JNI_FALSE;
934
935      ptr = getAdapter(env, index);
936      if (ptr != NULL) {
937        val = ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK ? JNI_TRUE : JNI_FALSE;
938        free(ptr);
939      }
940      return val;
941}
942
943/*
944 * Class:     java_net_NetworkInterface
945 * Method:    isP2P0
946 * Signature: (Ljava/lang/String;I)Z
947 */
948JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0_XP
949    (JNIEnv *env, jclass cls, jstring name, jint index) {
950      IP_ADAPTER_ADDRESSES *ptr;
951      jboolean val = JNI_FALSE;
952
953      ptr = getAdapter(env, index);
954      if (ptr != NULL) {
955        if (ptr->IfType == IF_TYPE_PPP || ptr->IfType == IF_TYPE_SLIP ||
956           ptr->IfType == IF_TYPE_TUNNEL) {
957          val = JNI_TRUE;
958        }
959        free(ptr);
960      }
961      return val;
962}
963