NetworkInterface.c revision 70da41603ee0dc5ab547c778003b3ed03ce3e6a1
1/*
2 * Copyright (c) 2000, 2011, 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
26
27#include <errno.h>
28#include <strings.h>
29#if defined(_ALLBSD_SOURCE) && defined(__OpenBSD__)
30#include <sys/types.h>
31#endif
32#include <netinet/in.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <arpa/inet.h>
38#include <net/if.h>
39#include <net/if_arp.h>
40
41#ifdef __solaris__
42#include <sys/dlpi.h>
43#include <fcntl.h>
44#include <stropts.h>
45#include <sys/sockio.h>
46#endif
47
48#ifdef __linux__
49#include <sys/ioctl.h>
50//#include <bits/ioctls.h>
51#include <sys/utsname.h>
52#include <stdio.h>
53#include <ifaddrs.h>
54#endif
55
56#ifdef __linux__
57#define _PATH_PROCNET_IFINET6           "/proc/net/if_inet6"
58#endif
59
60#if defined(_ALLBSD_SOURCE)
61#include <sys/param.h>
62#include <sys/ioctl.h>
63#include <sys/sockio.h>
64#if defined(__APPLE__)
65#include <net/ethernet.h>
66#include <net/if_var.h>
67#include <net/if_dl.h>
68#include <netinet/in_var.h>
69#include <ifaddrs.h>
70#endif
71#endif
72
73#include "jvm.h"
74#include "jni_util.h"
75#include "net_util.h"
76#include "JNIHelp.h"
77
78#define NATIVE_METHOD(className, functionName, signature) \
79{ #functionName, signature, (void*)(className ## _ ## functionName) }
80
81typedef struct _netaddr  {
82    struct sockaddr *addr;
83    struct sockaddr *brdcast;
84    short mask;
85    int family; /* to make searches simple */
86    struct _netaddr *next;
87} netaddr;
88
89typedef struct _netif {
90    char *name;
91    int index;
92    char virtual;
93    netaddr *addr;
94    struct _netif *childs;
95    struct _netif *next;
96} netif;
97
98/************************************************************************
99 * NetworkInterface
100 */
101
102
103/************************************************************************
104 * NetworkInterface
105 */
106jclass ni_class;
107jfieldID ni_nameID;
108jfieldID ni_indexID;
109jfieldID ni_descID;
110jfieldID ni_addrsID;
111jfieldID ni_bindsID;
112jfieldID ni_virutalID;
113jfieldID ni_childsID;
114jfieldID ni_parentID;
115jfieldID ni_defaultIndexID;
116jmethodID ni_ctrID;
117
118static jclass ni_iacls;
119static jclass ni_ia4cls;
120static jclass ni_ia6cls;
121static jclass ni_ibcls;
122static jmethodID ni_ia4ctrID;
123static jmethodID ni_ia6ctrID;
124static jmethodID ni_ibctrID;
125static jfieldID ni_ia6ipaddressID;
126static jfieldID ni_ibaddressID;
127static jfieldID ni_ib4broadcastID;
128static jfieldID ni_ib4maskID;
129
130/** Private methods declarations **/
131static jobject createNetworkInterface(JNIEnv *env, netif *ifs);
132static int     getFlags0(JNIEnv *env, jstring  ifname);
133
134static netif  *enumInterfaces(JNIEnv *env);
135
136#ifndef __linux__
137static netif  *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs);
138
139#ifdef AF_INET6
140static netif  *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs);
141#endif
142#endif
143
144static netif  *addif(JNIEnv *env, int sock, const char * if_name, netif *ifs, struct sockaddr* ifr_addrP, int family, short prefix);
145static void    freeif(netif *ifs);
146
147static int     openSocket(JNIEnv *env, int proto);
148static int     openSocketWithFallback(JNIEnv *env, const char *ifname);
149
150
151static struct  sockaddr *getBroadcast(JNIEnv *env, int sock, const char *name, struct sockaddr *brdcast_store);
152static short   getSubnet(JNIEnv *env, int sock, const char *ifname);
153static int     getIndex(int sock, const char *ifname);
154
155static int     getFlags(int sock, const char *ifname, int *flags);
156static int     getMacAddress(JNIEnv *env, int sock,  const char* ifname, const struct in_addr* addr, unsigned char *buf);
157static int     getMTU(JNIEnv *env, int sock, const char *ifname);
158
159
160
161#ifdef __solaris__
162static netif *enumIPvXInterfaces(JNIEnv *env, int sock, netif *ifs, int family);
163static int    getMacFromDevice(JNIEnv *env, const char* ifname, unsigned char* retbuf);
164
165#ifndef SIOCGLIFHWADDR
166#define SIOCGLIFHWADDR  _IOWR('i', 192, struct lifreq)
167#endif
168
169#endif
170
171/******************* Java entry points *****************************/
172
173/*
174 * Class:     java_net_NetworkInterface
175 * Method:    init
176 * Signature: ()V
177 */
178JNIEXPORT void JNICALL
179NetworkInterface_init(JNIEnv *env, jclass cls) {
180    ni_class = (*env)->FindClass(env,"java/net/NetworkInterface");
181    ni_class = (*env)->NewGlobalRef(env, ni_class);
182    ni_nameID = (*env)->GetFieldID(env, ni_class,"name", "Ljava/lang/String;");
183    ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
184    ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;");
185    ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;");
186    ni_descID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;");
187    ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z");
188    ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;");
189    ni_parentID = (*env)->GetFieldID(env, ni_class, "parent", "Ljava/net/NetworkInterface;");
190    ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
191
192    ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
193    ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
194    ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
195    ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
196    ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address");
197    ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls);
198    ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
199    ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
200    ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
201    ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V");
202    ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
203    ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B");
204    ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;");
205    ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;");
206    ni_ib4maskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
207    ni_defaultIndexID = (*env)->GetStaticFieldID(env, ni_class, "defaultIndex", "I");
208}
209
210
211/*
212 * Class:     java_net_NetworkInterface
213 * Method:    getByName0
214 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
215 */
216JNIEXPORT jobject JNICALL NetworkInterface_getByName0
217    (JNIEnv *env, jclass cls, jstring name) {
218
219    netif *ifs, *curr;
220    jboolean isCopy;
221    const char* name_utf;
222    jobject obj = NULL;
223
224    ifs = enumInterfaces(env);
225    if (ifs == NULL) {
226        return NULL;
227    }
228
229    name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
230
231    /*
232     * Search the list of interface based on name
233     */
234    curr = ifs;
235    while (curr != NULL) {
236        if (strcmp(name_utf, curr->name) == 0) {
237            break;
238        }
239        curr = curr->next;
240    }
241
242    /* if found create a NetworkInterface */
243    if (curr != NULL) {;
244        obj = createNetworkInterface(env, curr);
245    }
246
247    /* release the UTF string and interface list */
248    (*env)->ReleaseStringUTFChars(env, name, name_utf);
249    freeif(ifs);
250
251    return obj;
252}
253
254
255/*
256 * Class:     java_net_NetworkInterface
257 * Method:    getByIndex0
258 * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
259 */
260JNIEXPORT jobject JNICALL NetworkInterface_getByIndex0
261    (JNIEnv *env, jclass cls, jint index) {
262
263    netif *ifs, *curr;
264    jobject obj = NULL;
265
266    if (index <= 0) {
267        return NULL;
268    }
269
270    ifs = enumInterfaces(env);
271    if (ifs == NULL) {
272        return NULL;
273    }
274
275    /*
276     * Search the list of interface based on index
277     */
278    curr = ifs;
279    while (curr != NULL) {
280        if (index == curr->index) {
281            break;
282        }
283        curr = curr->next;
284    }
285
286    /* if found create a NetworkInterface */
287    if (curr != NULL) {;
288        obj = createNetworkInterface(env, curr);
289    }
290
291    freeif(ifs);
292    return obj;
293}
294
295/*
296 * Class:     java_net_NetworkInterface
297 * Method:    getByInetAddress0
298 * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
299 */
300JNIEXPORT jobject JNICALL NetworkInterface_getByInetAddress0
301    (JNIEnv *env, jclass cls, jobject iaObj) {
302
303    netif *ifs, *curr;
304
305#ifdef AF_INET6
306    int family = (getInetAddress_family(env, iaObj) == IPv4) ? AF_INET : AF_INET6;
307#else
308    int family =  AF_INET;
309#endif
310
311    jobject obj = NULL;
312    jboolean match = JNI_FALSE;
313
314    ifs = enumInterfaces(env);
315    if (ifs == NULL) {
316        return NULL;
317    }
318
319    curr = ifs;
320    while (curr != NULL) {
321        netaddr *addrP = curr->addr;
322
323        /*
324         * Iterate through each address on the interface
325         */
326        while (addrP != NULL) {
327
328            if (family == addrP->family) {
329                if (family == AF_INET) {
330                    int address1 = htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr);
331                    int address2 = getInetAddress_addr(env, iaObj);
332
333                    if (address1 == address2) {
334                        match = JNI_TRUE;
335                        break;
336                    }
337                }
338
339#ifdef AF_INET6
340                if (family == AF_INET6) {
341                    jbyte *bytes = (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr);
342                    jbyteArray ipaddress = (*env)->GetObjectField(env, iaObj, ni_ia6ipaddressID);
343                    jbyte caddr[16];
344                    int i;
345
346                    (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddr);
347                    i = 0;
348                    while (i < 16) {
349                        if (caddr[i] != bytes[i]) {
350                            break;
351                        }
352                        i++;
353                    }
354                    if (i >= 16) {
355                        match = JNI_TRUE;
356                        break;
357                    }
358                }
359#endif
360
361            }
362
363            if (match) {
364                break;
365            }
366            addrP = addrP->next;
367        }
368
369        if (match) {
370            break;
371        }
372        curr = curr->next;
373    }
374
375    /* if found create a NetworkInterface */
376    if (match) {;
377        obj = createNetworkInterface(env, curr);
378    }
379
380    freeif(ifs);
381    return obj;
382}
383
384
385/*
386 * Class:     java_net_NetworkInterface
387 * Method:    getAll
388 * Signature: ()[Ljava/net/NetworkInterface;
389 */
390JNIEXPORT jobjectArray JNICALL NetworkInterface_getAll
391    (JNIEnv *env, jclass cls) {
392
393    netif *ifs, *curr;
394    jobjectArray netIFArr;
395    jint arr_index, ifCount;
396
397    ifs = enumInterfaces(env);
398    if (ifs == NULL) {
399        return NULL;
400    }
401
402    /* count the interface */
403    ifCount = 0;
404    curr = ifs;
405    while (curr != NULL) {
406        ifCount++;
407        curr = curr->next;
408    }
409
410    /* allocate a NetworkInterface array */
411    netIFArr = (*env)->NewObjectArray(env, ifCount, cls, NULL);
412    if (netIFArr == NULL) {
413        freeif(ifs);
414        return NULL;
415    }
416
417    /*
418     * Iterate through the interfaces, create a NetworkInterface instance
419     * for each array element and populate the object.
420     */
421    curr = ifs;
422    arr_index = 0;
423    while (curr != NULL) {
424        jobject netifObj;
425
426        netifObj = createNetworkInterface(env, curr);
427        if (netifObj == NULL) {
428            freeif(ifs);
429            return NULL;
430        }
431
432        /* put the NetworkInterface into the array */
433        (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
434
435        curr = curr->next;
436    }
437
438    freeif(ifs);
439    return netIFArr;
440}
441
442
443/*
444 * Class:     java_net_NetworkInterface
445 * Method:    isUp0
446 * Signature: (Ljava/lang/String;I)Z
447 */
448JNIEXPORT jboolean JNICALL NetworkInterface_isUp0(JNIEnv *env, jclass cls, jstring name, jint index) {
449    int ret = getFlags0(env, name);
450    return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE :  JNI_FALSE;
451}
452
453/*
454 * Class:     java_net_NetworkInterface
455 * Method:    isP2P0
456 * Signature: (Ljava/lang/String;I)Z
457 */
458JNIEXPORT jboolean JNICALL NetworkInterface_isP2P0(JNIEnv *env, jclass cls, jstring name, jint index) {
459    int ret = getFlags0(env, name);
460    return (ret & IFF_POINTOPOINT) ? JNI_TRUE :  JNI_FALSE;
461}
462
463/*
464 * Class:     java_net_NetworkInterface
465 * Method:    isLoopback0
466 * Signature: (Ljava/lang/String;I)Z
467 */
468JNIEXPORT jboolean JNICALL NetworkInterface_isLoopback0(JNIEnv *env, jclass cls, jstring name, jint index) {
469  int ret = getFlags0(env, name);
470  return (ret & IFF_LOOPBACK) ? JNI_TRUE :  JNI_FALSE;
471}
472
473/*
474 * Class:     java_net_NetworkInterface
475 * Method:    supportsMulticast0
476 * Signature: (Ljava/lang/String;I)Z
477 */
478JNIEXPORT jboolean JNICALL NetworkInterface_supportsMulticast0(JNIEnv *env, jclass cls, jstring name, jint index) {
479  int ret = getFlags0(env, name);
480  return (ret & IFF_MULTICAST) ? JNI_TRUE :  JNI_FALSE;
481}
482
483/*
484 * Class:     java_net_NetworkInterface
485 * Method:    getMacAddr0
486 * Signature: ([bLjava/lang/String;I)[b
487 */
488JNIEXPORT jbyteArray JNICALL NetworkInterface_getMacAddr0(JNIEnv *env, jclass class, jbyteArray addrArray, jstring name, jint index) {
489  jint addr;
490  jbyte caddr[4];
491  struct in_addr iaddr;
492  jbyteArray ret = NULL;
493  unsigned char mac[16];
494  int len;
495  int sock;
496  jboolean isCopy;
497  const char* name_utf;
498
499  name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
500
501  if ((sock =openSocketWithFallback(env, name_utf)) < 0) {
502    (*env)->ReleaseStringUTFChars(env, name, name_utf);
503    return JNI_FALSE;
504  }
505
506
507  if (!IS_NULL(addrArray)) {
508    (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
509    addr = ((caddr[0]<<24) & 0xff000000);
510    addr |= ((caddr[1] <<16) & 0xff0000);
511    addr |= ((caddr[2] <<8) & 0xff00);
512    addr |= (caddr[3] & 0xff);
513    iaddr.s_addr = htonl(addr);
514    len = getMacAddress(env, sock, name_utf, &iaddr, mac);
515  } else {
516    len = getMacAddress(env, sock, name_utf,NULL, mac);
517  }
518  if (len > 0) {
519    ret = (*env)->NewByteArray(env, len);
520    if (IS_NULL(ret)) {
521      /* we may have memory to free at the end of this */
522      goto fexit;
523    }
524    (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) (mac));
525  }
526fexit:
527  /* release the UTF string and interface list */
528  (*env)->ReleaseStringUTFChars(env, name, name_utf);
529
530  close(sock);
531  return ret;
532}
533
534/*
535 * Class:       java_net_NetworkInterface
536 * Method:      getMTU0
537 * Signature:   ([bLjava/lang/String;I)I
538 */
539
540JNIEXPORT jint JNICALL NetworkInterface_getMTU0(JNIEnv *env, jclass class, jstring name, jint index) {
541  jboolean isCopy;
542  int ret = -1;
543  int sock;
544  const char* name_utf;
545
546  name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
547
548  if ((sock =openSocketWithFallback(env, name_utf)) < 0) {
549    (*env)->ReleaseStringUTFChars(env, name, name_utf);
550    return JNI_FALSE;
551  }
552
553  ret = getMTU(env, sock, name_utf);
554
555  (*env)->ReleaseStringUTFChars(env, name, name_utf);
556
557  close(sock);
558  return ret;
559}
560
561/*** Private methods definitions ****/
562
563static int getFlags0(JNIEnv *env, jstring name) {
564  jboolean isCopy;
565  int ret, sock;
566  const char* name_utf;
567  int flags = 0;
568
569  name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
570
571  if ((sock = openSocketWithFallback(env, name_utf)) < 0) {
572    (*env)->ReleaseStringUTFChars(env, name, name_utf);
573    return -1;
574  }
575
576  name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
577
578  ret = getFlags(sock, name_utf, &flags);
579
580  close(sock);
581  (*env)->ReleaseStringUTFChars(env, name, name_utf);
582
583  if (ret < 0) {
584    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL  SIOCGLIFFLAGS failed");
585    return -1;
586  }
587
588  return flags;
589}
590
591
592
593
594/*
595 * Create a NetworkInterface object, populate the name and index, and
596 * populate the InetAddress array based on the IP addresses for this
597 * interface.
598 */
599jobject createNetworkInterface(JNIEnv *env, netif *ifs) {
600  jobject netifObj;
601  jobject name;
602  jobjectArray addrArr;
603  jobjectArray bindArr;
604  jobjectArray childArr;
605  netaddr *addrs;
606  jint addr_index, addr_count, bind_index;
607  jint child_count, child_index;
608  netaddr *addrP;
609  netif *childP;
610  jobject tmp;
611
612  /*
613   * Create a NetworkInterface object and populate it
614   */
615  netifObj = (*env)->NewObject(env, ni_class, ni_ctrID);
616  name = (*env)->NewStringUTF(env, ifs->name);
617  if (netifObj == NULL || name == NULL) {
618    return NULL;
619  }
620  (*env)->SetObjectField(env, netifObj, ni_nameID, name);
621  (*env)->SetObjectField(env, netifObj, ni_descID, name);
622  (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
623  (*env)->SetBooleanField(env, netifObj, ni_virutalID, ifs->virtual ? JNI_TRUE : JNI_FALSE);
624
625  /*
626   * Count the number of address on this interface
627   */
628  addr_count = 0;
629  addrP = ifs->addr;
630  while (addrP != NULL) {
631    addr_count++;
632    addrP = addrP->next;
633  }
634
635  /*
636   * Create the array of InetAddresses
637   */
638  addrArr = (*env)->NewObjectArray(env, addr_count,  ni_iacls, NULL);
639  if (addrArr == NULL) {
640    return NULL;
641  }
642
643  bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL);
644  if (bindArr == NULL) {
645    return NULL;
646  }
647  addrP = ifs->addr;
648  addr_index = 0;
649  bind_index = 0;
650  while (addrP != NULL) {
651    jobject iaObj = NULL;
652    jobject ibObj = NULL;
653
654    if (addrP->family == AF_INET) {
655      iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
656      if (iaObj) {
657        setInetAddress_addr(env, iaObj, htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr));
658      }
659      ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
660      if (ibObj) {
661        (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
662        if (addrP->brdcast) {
663          jobject ia2Obj = NULL;
664          ia2Obj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
665          if (ia2Obj) {
666            setInetAddress_addr(env, ia2Obj, htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr));
667            (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj);
668            (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
669          }
670        }
671        (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
672      }
673    }
674
675#ifdef AF_INET6
676    if (addrP->family == AF_INET6) {
677      int scope=0;
678      iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
679      if (iaObj) {
680        jbyteArray ipaddress = (*env)->NewByteArray(env, 16);
681        if (ipaddress == NULL) {
682          return NULL;
683        }
684        (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
685                                   (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr));
686
687        scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;
688
689        if (scope != 0) { /* zero is default value, no need to set */
690          (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
691          (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
692          (*env)->SetObjectField(env, iaObj, ia6_scopeifnameID, netifObj);
693        }
694        (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress);
695      }
696      ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
697      if (ibObj) {
698        (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
699        (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
700        (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
701      }
702    }
703#endif
704
705    if (iaObj == NULL) {
706      return NULL;
707    }
708
709    (*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj);
710    addrP = addrP->next;
711  }
712
713  /*
714   * See if there is any virtual interface attached to this one.
715   */
716  child_count = 0;
717  childP = ifs->childs;
718  while (childP) {
719    child_count++;
720    childP = childP->next;
721  }
722
723  childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL);
724  if (childArr == NULL) {
725    return NULL;
726  }
727
728  /*
729   * Create the NetworkInterface instances for the sub-interfaces as
730   * well.
731   */
732  child_index = 0;
733  childP = ifs->childs;
734  while(childP) {
735    tmp = createNetworkInterface(env, childP);
736    if (tmp == NULL) {
737      return NULL;
738    }
739    (*env)->SetObjectField(env, tmp, ni_parentID, netifObj);
740    (*env)->SetObjectArrayElement(env, childArr, child_index++, tmp);
741    childP = childP->next;
742  }
743  (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
744  (*env)->SetObjectField(env, netifObj, ni_bindsID, bindArr);
745  (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
746
747  /* return the NetworkInterface */
748  return netifObj;
749}
750
751#ifdef __linux__
752#ifdef AF_INET6
753/*
754 * Determines the prefix for IPv6 interfaces.
755 */
756static
757int prefix(void *val, int size) {
758  u_char *name = (u_char *)val;
759  int byte, bit, plen = 0;
760
761  for (byte = 0; byte < size && name[byte] == 0xff; byte++) {
762    plen += 8;
763  }
764  if (byte < size) {
765    for (bit = 7; bit > 0; bit--) {
766      if (name[byte] & (1 << bit)) plen++;
767    }
768  }
769  return plen;
770}
771#endif
772
773/*
774 * Enumerates all interfaces
775 */
776static netif *enumInterfaces(JNIEnv *env) {
777  netif *ifs = NULL;
778  struct ifaddrs *ifa, *origifa;
779
780  int sock = 0;
781  if ((sock = openSocket(env, AF_INET)) < 0 && (*env)->ExceptionOccurred(env)) {
782    return NULL;
783  }
784
785#ifdef AF_INET6
786  int sock6 = 0;
787  if (ipv6_available()) {
788    if ((sock6 = openSocket(env, AF_INET6)) < 0 && (*env)->ExceptionOccurred(env)) {
789      return NULL;
790    }
791  }
792#endif
793
794  if (getifaddrs(&origifa) != 0) {
795    NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException",
796                                 "getifaddrs() function failed");
797    return ifs;
798  }
799
800  for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
801    if (ifa->ifa_addr != NULL) {
802      switch (ifa->ifa_addr->sa_family) {
803        case AF_PACKET:
804          ifs = addif(env, 0, ifa->ifa_name, ifs, 0, AF_PACKET, 0);
805          break;
806        case AF_INET:
807          ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, AF_INET, 0);
808          break;
809#ifdef AF_INET6
810        case AF_INET6:
811          if (ipv6_available()) {
812            struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr;
813            ifs = addif(env, sock6, ifa->ifa_name, ifs, ifa->ifa_addr, AF_INET6,
814                        prefix(&sin6->sin6_addr, sizeof(struct in6_addr)));
815          }
816          break;
817#endif
818      }
819    }
820  }
821
822  if (close(sock) != 0 && (*env)->ExceptionOccurred(env)) {
823    freeif(ifs);
824    return NULL;
825  }
826
827#ifdef AF_INET6
828  if (ipv6_available()) {
829    if (close(sock6) != 0 && (*env)->ExceptionOccurred(env)) {
830      freeif(ifs);
831      return NULL;
832    }
833  }
834#endif
835
836  return ifs;
837}
838#else
839static netif *enumInterfaces(JNIEnv *env) {
840  netif *ifs;
841  int sock;
842
843  /*
844   * Enumerate IPv4 addresses
845   */
846
847  sock = openSocket(env, AF_INET);
848  if (sock < 0 && (*env)->ExceptionOccurred(env)) {
849    return NULL;
850  }
851
852  ifs = enumIPv4Interfaces(env, sock, NULL);
853  close(sock);
854
855  if (ifs == NULL && (*env)->ExceptionOccurred(env)) {
856    return NULL;
857  }
858
859  /* return partial list if exception occure in the middle of process ???*/
860
861  /*
862   * If IPv6 is available then enumerate IPv6 addresses.
863   */
864#ifdef AF_INET6
865
866  /* User can disable ipv6 expicitly by -Djava.net.preferIPv4Stack=true,
867   * so we have to call ipv6_available()
868   */
869  if (ipv6_available()) {
870
871    sock =  openSocket(env, AF_INET6);
872    if (sock < 0 && (*env)->ExceptionOccurred(env)) {
873      freeif(ifs);
874      return NULL;
875    }
876
877    ifs = enumIPv6Interfaces(env, sock, ifs);
878    close(sock);
879
880    if ((*env)->ExceptionOccurred(env)) {
881      freeif(ifs);
882      return NULL;
883    }
884
885  }
886#endif
887
888  return ifs;
889}
890#endif
891
892#define CHECKED_MALLOC3(_pointer,_type,_size) \
893    do{ \
894      _pointer = (_type)malloc( _size ); \
895      if (_pointer == NULL) { \
896        JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \
897        return ifs; /* return untouched list */ \
898      } \
899    } while(0)
900
901
902/*
903 * Free an interface list (including any attached addresses)
904 */
905void freeif(netif *ifs) {
906  netif *currif = ifs;
907  netif *child = NULL;
908
909  while (currif != NULL) {
910    netaddr *addrP = currif->addr;
911    while (addrP != NULL) {
912      netaddr *next = addrP->next;
913      free(addrP);
914      addrP = next;
915    }
916
917    /*
918     * Don't forget to free the sub-interfaces.
919     */
920    if (currif->childs != NULL) {
921      freeif(currif->childs);
922    }
923
924    ifs = currif->next;
925    free(currif);
926    currif = ifs;
927  }
928}
929
930netif *addif(JNIEnv *env, int sock, const char * if_name,
931             netif *ifs, struct sockaddr* ifr_addrP, int family,
932             short prefix)
933{
934  netif *currif = ifs, *parent;
935  netaddr *addrP = NULL;
936
937#ifdef LIFNAMSIZ
938  int ifnam_size = LIFNAMSIZ;
939  char name[LIFNAMSIZ], vname[LIFNAMSIZ];
940#else
941  int ifnam_size = IFNAMSIZ;
942  char name[IFNAMSIZ], vname[IFNAMSIZ];
943#endif
944
945  char  *name_colonP;
946  int mask;
947  int isVirtual = 0;
948  int addr_size;
949  int flags = 0;
950
951  /*
952   * If the interface name is a logical interface then we
953   * remove the unit number so that we have the physical
954   * interface (eg: hme0:1 -> hme0). NetworkInterface
955   * currently doesn't have any concept of physical vs.
956   * logical interfaces.
957   */
958  strncpy(name, if_name, ifnam_size);
959  name[ifnam_size - 1] = '\0';
960  *vname = 0;
961
962  /*
963   * Create and populate the netaddr node. If allocation fails
964   * return an un-updated list.
965   */
966  /*Allocate for addr and brdcast at once*/
967
968  switch(family) {
969    case AF_INET:
970      addr_size = sizeof(struct sockaddr_in);
971      break;
972#ifdef AF_INET6
973    case AF_INET6:
974      addr_size = sizeof(struct sockaddr_in6);
975      break;
976#endif
977    case AF_PACKET:
978      addr_size = 0;
979      break;
980    default:
981      return NULL;
982  }
983
984  if (addr_size > 0) {
985    CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr)+2*addr_size);
986    addrP->addr = (struct sockaddr *)( (char *) addrP+sizeof(netaddr) );
987    memcpy(addrP->addr, ifr_addrP, addr_size);
988
989    addrP->family = family;
990    addrP->brdcast = NULL;
991    addrP->mask = prefix;
992    addrP->next = 0;
993    if (family == AF_INET) {
994      /*
995       * Deal with brodcast addr & subnet mask
996       */
997      struct sockaddr * brdcast_to = (struct sockaddr *) ((char *) addrP + sizeof(netaddr) + addr_size);
998      addrP->brdcast = getBroadcast(env, sock, name,  brdcast_to );
999
1000      if (addrP->brdcast && (mask = getSubnet(env, sock, name)) != -1) {
1001        addrP->mask = mask;
1002      }
1003    }
1004  }
1005
1006  /**
1007   * Deal with virtual interface with colon notaion e.g. eth0:1
1008   */
1009  name_colonP = strchr(name, ':');
1010  if (name_colonP != NULL) {
1011    /**
1012     * This is a virtual interface. If we are able to access the parent
1013     * we need to create a new entry if it doesn't exist yet *and* update
1014     * the 'parent' interface with the new records.
1015     */
1016    *name_colonP = 0;
1017    if (getFlags(sock, name, &flags) < 0 || flags < 0) {
1018      // failed to access parent interface do not create parent.
1019      // We are a virtual interface with no parent.
1020      isVirtual = 1;
1021      *name_colonP = ':';
1022    }
1023    else{
1024      // Got access to parent, so create it if necessary.
1025      // Save original name to vname and truncate name by ':'
1026      memcpy(vname, name, sizeof(vname) );
1027      vname[name_colonP - name] = ':';
1028    }
1029  }
1030
1031  /*
1032   * Check if this is a "new" interface. Use the interface
1033   * name for matching because index isn't supported on
1034   * Solaris 2.6 & 7.
1035   */
1036  while (currif != NULL) {
1037    if (strcmp(name, currif->name) == 0) {
1038      break;
1039    }
1040    currif = currif->next;
1041  }
1042
1043  /*
1044   * If "new" then create an netif structure and
1045   * insert it onto the list.
1046   */
1047  if (currif == NULL) {
1048    CHECKED_MALLOC3(currif, netif *, sizeof(netif) + ifnam_size);
1049    currif->name = (char *) currif+sizeof(netif);
1050    strncpy(currif->name, name, ifnam_size);
1051    currif->name[ifnam_size - 1] = '\0';
1052    currif->index = getIndex(sock, name);
1053    currif->addr = NULL;
1054    currif->childs = NULL;
1055    currif->virtual = isVirtual;
1056    currif->next = ifs;
1057    ifs = currif;
1058  }
1059
1060  /*
1061   * Finally insert the address on the interface
1062   */
1063  if (addrP != NULL)
1064    addrP->next = currif->addr;
1065  currif->addr = addrP;
1066
1067  parent = currif;
1068
1069  /**
1070   * Let's deal with the virtual interface now.
1071   */
1072  if (vname[0]) {
1073    netaddr *tmpaddr;
1074
1075    currif = parent->childs;
1076
1077    while (currif != NULL) {
1078      if (strcmp(vname, currif->name) == 0) {
1079        break;
1080      }
1081      currif = currif->next;
1082    }
1083
1084    if (currif == NULL) {
1085      CHECKED_MALLOC3(currif, netif *, sizeof(netif) + ifnam_size);
1086      currif->name = (char *) currif + sizeof(netif);
1087      strncpy(currif->name, vname, ifnam_size);
1088      currif->name[ifnam_size - 1] = '\0';
1089      currif->index = getIndex(sock, vname);
1090      currif->addr = NULL;
1091      /* Need to duplicate the addr entry? */
1092      currif->virtual = 1;
1093      currif->childs = NULL;
1094      currif->next = parent->childs;
1095      parent->childs = currif;
1096    }
1097
1098    CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr)+2*addr_size);
1099    memcpy(tmpaddr, addrP, sizeof(netaddr));
1100    if (addrP->addr != NULL) {
1101      tmpaddr->addr = (struct sockaddr *) ( (char*)tmpaddr + sizeof(netaddr) ) ;
1102      memcpy(tmpaddr->addr, addrP->addr, addr_size);
1103    }
1104
1105    if (addrP->brdcast != NULL) {
1106      tmpaddr->brdcast = (struct sockaddr *) ((char *) tmpaddr + sizeof(netaddr)+addr_size);
1107      memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size);
1108    }
1109
1110    tmpaddr->next = currif->addr;
1111    currif->addr = tmpaddr;
1112  }
1113
1114  return ifs;
1115}
1116
1117/* Open socket for further ioct calls
1118 * proto is AF_INET/AF_INET6
1119 */
1120static int  openSocket(JNIEnv *env, int proto){
1121  int sock;
1122
1123  if ((sock = JVM_Socket(proto, SOCK_DGRAM, 0)) < 0) {
1124    /*
1125     * If EPROTONOSUPPORT is returned it means we don't have
1126     * support  for this proto so don't throw an exception.
1127     */
1128    if (errno != EPROTONOSUPPORT) {
1129      NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "Socket creation failed");
1130    }
1131    return -1;
1132  }
1133
1134  return sock;
1135}
1136
1137
1138/** Linux **/
1139#ifdef __linux__
1140/* Open socket for further ioct calls, try v4 socket first and
1141 * if it falls return v6 socket
1142 */
1143
1144#ifdef AF_INET6
1145static int openSocketWithFallback(JNIEnv *env, const char *ifname){
1146  int sock;
1147  struct ifreq if2;
1148
1149  if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1150    if (errno == EPROTONOSUPPORT){
1151      if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
1152        NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1153        return -1;
1154      }
1155    }
1156    else{ // errno is not NOSUPPORT
1157      NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1158      return -1;
1159    }
1160  }
1161
1162  /* Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or IPv6 socket regardless of type
1163     of address of an interface */
1164
1165  return sock;
1166}
1167
1168#else
1169static int openSocketWithFallback(JNIEnv *env, const char *ifname){
1170  return openSocket(env,AF_INET);
1171}
1172#endif
1173static int getIndex(int sock, const char *name){
1174  /*
1175   * Try to get the interface index
1176   * (Not supported on Solaris 2.6 or 7)
1177   */
1178  struct ifreq if2;
1179  strcpy(if2.ifr_name, name);
1180
1181  if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
1182    return -1;
1183  }
1184
1185  return if2.ifr_ifindex;
1186}
1187
1188/**
1189 * Returns the IPv4 broadcast address of a named interface, if it exists.
1190 * Returns 0 if it doesn't have one.
1191 */
1192static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) {
1193  struct sockaddr *ret = NULL;
1194  struct ifreq if2;
1195
1196  memset((char *) &if2, 0, sizeof(if2));
1197  strcpy(if2.ifr_name, ifname);
1198
1199  /* Let's make sure the interface does have a broadcast address */
1200  if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2)  < 0) {
1201    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL  SIOCGIFFLAGS failed");
1202    return ret;
1203  }
1204
1205  if (if2.ifr_flags & IFF_BROADCAST) {
1206    /* It does, let's retrieve it*/
1207    if (ioctl(sock, SIOCGIFBRDADDR, (char *)&if2) < 0) {
1208      NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFBRDADDR failed");
1209      return ret;
1210    }
1211
1212    ret = brdcast_store;
1213    memcpy(ret, &if2.ifr_broadaddr, sizeof(struct sockaddr));
1214  }
1215
1216  return ret;
1217}
1218
1219/**
1220 * Returns the IPv4 subnet prefix length (aka subnet mask) for the named
1221 * interface, if it has one, otherwise return -1.
1222 */
1223static short getSubnet(JNIEnv *env, int sock, const char *ifname) {
1224  unsigned int mask;
1225  short ret;
1226  struct ifreq if2;
1227
1228  memset((char *) &if2, 0, sizeof(if2));
1229  strcpy(if2.ifr_name, ifname);
1230
1231  if (ioctl(sock, SIOCGIFNETMASK, (char *)&if2) < 0) {
1232    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFNETMASK failed");
1233    return -1;
1234  }
1235
1236  mask = ntohl(((struct sockaddr_in*)&(if2.ifr_addr))->sin_addr.s_addr);
1237  ret = 0;
1238  while (mask) {
1239    mask <<= 1;
1240    ret++;
1241  }
1242
1243  return ret;
1244}
1245
1246/**
1247 * Get the Hardware address (usually MAC address) for the named interface.
1248 * return puts the data in buf, and returns the length, in byte, of the
1249 * MAC address. Returns -1 if there is no hardware address on that interface.
1250 */
1251static int getMacAddress(JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr, unsigned char *buf) {
1252  static struct ifreq ifr;
1253  int i;
1254
1255  strcpy(ifr.ifr_name, ifname);
1256  if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
1257    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFHWADDR failed");
1258    return -1;
1259  }
1260
1261  memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
1262
1263  /*
1264   * All bytes to 0 means no hardware address.
1265   */
1266
1267  for (i = 0; i < IFHWADDRLEN; i++) {
1268    if (buf[i] != 0)
1269      return IFHWADDRLEN;
1270  }
1271
1272  return -1;
1273}
1274
1275static int getMTU(JNIEnv *env, int sock,  const char *ifname) {
1276  struct ifreq if2;
1277
1278  memset((char *) &if2, 0, sizeof(if2));
1279  strcpy(if2.ifr_name, ifname);
1280
1281  if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
1282    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFMTU failed");
1283    return -1;
1284  }
1285
1286  return  if2.ifr_mtu;
1287}
1288
1289static int getFlags(int sock, const char *ifname, int *flags) {
1290  struct ifreq if2;
1291
1292  memset((char *) &if2, 0, sizeof(if2));
1293  strcpy(if2.ifr_name, ifname);
1294
1295  if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0){
1296    return -1;
1297  }
1298
1299  if (sizeof(if2.ifr_flags) == sizeof(short)) {
1300    *flags = (if2.ifr_flags & 0xffff);
1301  } else {
1302    *flags = if2.ifr_flags;
1303  }
1304  return 0;
1305}
1306
1307#endif
1308
1309/** Solaris **/
1310#ifdef __solaris__
1311/* Open socket for further ioct calls, try v4 socket first and
1312 * if it falls return v6 socket
1313 */
1314
1315#ifdef AF_INET6
1316static int openSocketWithFallback(JNIEnv *env, const char *ifname){
1317  int sock, alreadyV6 = 0;
1318  struct lifreq if2;
1319
1320  if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1321    if (errno == EPROTONOSUPPORT){
1322      if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
1323        NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1324        return -1;
1325      }
1326
1327      alreadyV6=1;
1328    }
1329    else{ // errno is not NOSUPPORT
1330      NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1331      return -1;
1332    }
1333  }
1334
1335  /**
1336   * Solaris requires that we have IPv6 socket to query an
1337   * interface without IPv4 address - check it here
1338   * POSIX 1 require the kernell to return ENOTTY if the call is
1339   * unappropriate for device e.g. NETMASK for device having IPv6
1340   * only address but not all devices follows the standart so
1341   * fallback on any error.  It's not an ecology friendly but more
1342   * reliable.
1343   */
1344
1345  if (! alreadyV6 ){
1346    memset((char *) &if2, 0, sizeof(if2));
1347    strcpy(if2.lifr_name, ifname);
1348    if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
1349      close(sock);
1350      if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
1351        NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1352        return -1;
1353      }
1354    }
1355  }
1356
1357  return sock;
1358}
1359
1360#else
1361static int openSocketWithFallback(JNIEnv *env, const char *ifname){
1362  return openSocket(env,AF_INET);
1363}
1364#endif
1365
1366/*
1367 * Enumerates and returns all IPv4 interfaces
1368 * (linux verison)
1369 */
1370
1371static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
1372  return enumIPvXInterfaces(env,sock, ifs, AF_INET);
1373}
1374
1375#ifdef AF_INET6
1376static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
1377  return enumIPvXInterfaces(env,sock, ifs, AF_INET6);
1378}
1379#endif
1380
1381/*
1382   Enumerates and returns all interfaces on Solaris
1383   use the same code for IPv4 and IPv6
1384   */
1385static netif *enumIPvXInterfaces(JNIEnv *env, int sock, netif *ifs, int family) {
1386  struct lifconf ifc;
1387  struct lifreq *ifr;
1388  int n;
1389  char *buf;
1390  struct lifnum numifs;
1391  unsigned bufsize;
1392
1393  /*
1394   * Get the interface count
1395   */
1396  numifs.lifn_family = family;
1397  numifs.lifn_flags = 0;
1398  if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {
1399    NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGLIFNUM failed");
1400    return ifs;
1401  }
1402
1403  /*
1404   *  Enumerate the interface configurations
1405   */
1406  bufsize = numifs.lifn_count * sizeof (struct lifreq);
1407  CHECKED_MALLOC3(buf, char *, bufsize);
1408
1409  ifc.lifc_family = family;
1410  ifc.lifc_flags = 0;
1411  ifc.lifc_len = bufsize;
1412  ifc.lifc_buf = buf;
1413  if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {
1414    NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGLIFCONF failed");
1415    free(buf);
1416    return ifs;
1417  }
1418
1419  /*
1420   * Iterate through each interface
1421   */
1422  ifr = ifc.lifc_req;
1423  for (n=0; n<numifs.lifn_count; n++, ifr++) {
1424    int index = -1;
1425    struct lifreq if2;
1426
1427    /*
1428     * Ignore either IPv4 or IPv6 addresses
1429     */
1430    if (ifr->lifr_addr.ss_family != family) {
1431      continue;
1432    }
1433
1434#ifdef AF_INET6
1435    if (ifr->lifr_addr.ss_family == AF_INET6) {
1436      struct sockaddr_in6 *s6= (struct sockaddr_in6 *)&(ifr->lifr_addr);
1437      s6->sin6_scope_id = getIndex(sock, ifr->lifr_name);
1438    }
1439#endif
1440
1441    /* add to the list */
1442    ifs = addif(env, sock,ifr->lifr_name, ifs, (struct sockaddr *)&(ifr->lifr_addr),family, (short) ifr->lifr_addrlen);
1443
1444    /*
1445     * If an exception occurred we return immediately
1446     */
1447    if ((*env)->ExceptionOccurred(env)) {
1448      free(buf);
1449      return ifs;
1450    }
1451
1452  }
1453
1454  free(buf);
1455  return ifs;
1456}
1457
1458static int getIndex(int sock, const char *name){
1459  /*
1460   * Try to get the interface index
1461   * (Not supported on Solaris 2.6 or 7)
1462   */
1463  struct lifreq if2;
1464  strcpy(if2.lifr_name, name);
1465
1466  if (ioctl(sock, SIOCGLIFINDEX, (char *)&if2) < 0) {
1467    return -1;
1468  }
1469
1470  return if2.lifr_index;
1471}
1472
1473/**
1474 * Returns the IPv4 broadcast address of a named interface, if it exists.
1475 * Returns 0 if it doesn't have one.
1476 */
1477static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) {
1478  struct sockaddr *ret = NULL;
1479  struct lifreq if2;
1480
1481  memset((char *) &if2, 0, sizeof(if2));
1482  strcpy(if2.lifr_name, ifname);
1483
1484  /* Let's make sure the interface does have a broadcast address */
1485  if (ioctl(sock, SIOCGLIFFLAGS, (char *)&if2)  < 0) {
1486    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL  SIOCGLIFFLAGS failed");
1487    return ret;
1488  }
1489
1490  if (if2.lifr_flags & IFF_BROADCAST) {
1491    /* It does, let's retrieve it*/
1492    if (ioctl(sock, SIOCGLIFBRDADDR, (char *)&if2) < 0) {
1493      NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFBRDADDR failed");
1494      return ret;
1495    }
1496
1497    ret = brdcast_store;
1498    memcpy(ret, &if2.lifr_broadaddr, sizeof(struct sockaddr));
1499  }
1500
1501  return ret;
1502}
1503
1504/**
1505 * Returns the IPv4 subnet prefix length (aka subnet mask) for the named
1506 * interface, if it has one, otherwise return -1.
1507 */
1508static short getSubnet(JNIEnv *env, int sock, const char *ifname) {
1509  unsigned int mask;
1510  short ret;
1511  struct lifreq if2;
1512
1513  memset((char *) &if2, 0, sizeof(if2));
1514  strcpy(if2.lifr_name, ifname);
1515
1516  if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
1517    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFNETMASK failed");
1518    return -1;
1519  }
1520
1521  mask = ntohl(((struct sockaddr_in*)&(if2.lifr_addr))->sin_addr.s_addr);
1522  ret = 0;
1523
1524  while (mask) {
1525    mask <<= 1;
1526    ret++;
1527  }
1528
1529  return ret;
1530}
1531
1532
1533
1534#define DEV_PREFIX  "/dev/"
1535
1536/**
1537 * Solaris specific DLPI code to get hardware address from a device.
1538 * Unfortunately, at least up to Solaris X, you have to have special
1539 * privileges (i.e. be root).
1540 */
1541static int getMacFromDevice(JNIEnv *env, const char* ifname, unsigned char* retbuf) {
1542  char style1dev[MAXPATHLEN];
1543  int fd;
1544  dl_phys_addr_req_t dlpareq;
1545  dl_phys_addr_ack_t *dlpaack;
1546  struct strbuf msg;
1547  char buf[128];
1548  int flags = 0;
1549
1550  /**
1551   * Device is in /dev
1552   * e.g.: /dev/bge0
1553   */
1554  strcpy(style1dev, DEV_PREFIX);
1555  strcat(style1dev, ifname);
1556  if ((fd = open(style1dev, O_RDWR)) < 0) {
1557    /*
1558     * Can't open it. We probably are missing the privilege.
1559     * We'll have to try something else
1560     */
1561    return 0;
1562  }
1563
1564  dlpareq.dl_primitive = DL_PHYS_ADDR_REQ;
1565  dlpareq.dl_addr_type = DL_CURR_PHYS_ADDR;
1566
1567  msg.buf = (char *)&dlpareq;
1568  msg.len = DL_PHYS_ADDR_REQ_SIZE;
1569
1570  if (putmsg(fd, &msg, NULL, 0) < 0) {
1571    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "putmsg failed");
1572    return -1;
1573  }
1574
1575  dlpaack = (dl_phys_addr_ack_t *)buf;
1576
1577  msg.buf = (char *)buf;
1578  msg.len = 0;
1579  msg.maxlen = sizeof (buf);
1580  if (getmsg(fd, &msg, NULL, &flags) < 0) {
1581    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "getmsg failed");
1582    return -1;
1583  }
1584
1585  if (msg.len < DL_PHYS_ADDR_ACK_SIZE || dlpaack->dl_primitive != DL_PHYS_ADDR_ACK) {
1586    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Couldn't obtain phys addr\n");
1587    return -1;
1588  }
1589
1590  memcpy(retbuf, &buf[dlpaack->dl_addr_offset], dlpaack->dl_addr_length);
1591  return dlpaack->dl_addr_length;
1592}
1593
1594/**
1595 * Get the Hardware address (usually MAC address) for the named interface.
1596 * return puts the data in buf, and returns the length, in byte, of the
1597 * MAC address. Returns -1 if there is no hardware address on that interface.
1598 */
1599static int getMacAddress(JNIEnv *env, int sock, const char *ifname,  const struct in_addr* addr, unsigned char *buf) {
1600  struct arpreq arpreq;
1601  struct sockaddr_in* sin;
1602  struct sockaddr_in ipAddr;
1603  int len, i;
1604  struct lifreq lif;
1605
1606  /* First, try the new (S11) SIOCGLIFHWADDR ioctl(). If that fails
1607   * try the old way.
1608   */
1609  memset(&lif, 0, sizeof(lif));
1610  strlcpy(lif.lifr_name, ifname, sizeof(lif.lifr_name));
1611
1612  if (ioctl(sock, SIOCGLIFHWADDR, &lif) != -1) {
1613    struct sockaddr_dl *sp;
1614    sp = (struct sockaddr_dl *)&lif.lifr_addr;
1615    memcpy(buf, &sp->sdl_data[0], sp->sdl_alen);
1616    return sp->sdl_alen;
1617  }
1618
1619  /**
1620   * On Solaris we have to use DLPI, but it will only work if we have
1621   * privileged access (i.e. root). If that fails, we try a lookup
1622   * in the ARP table, which requires an IPv4 address.
1623   */
1624  if ((len = getMacFromDevice(env, ifname, buf))  == 0) {
1625    /*DLPI failed - trying to do arp lookup*/
1626
1627    if (addr == NULL) {
1628      /**
1629       * No IPv4 address for that interface, so can't do an ARP lookup.
1630       */
1631      return -1;
1632    }
1633
1634    len = 6; //???
1635
1636    sin = (struct sockaddr_in *) &arpreq.arp_pa;
1637    memset((char *) &arpreq, 0, sizeof(struct arpreq));
1638    ipAddr.sin_port = 0;
1639    ipAddr.sin_family = AF_INET;
1640    memcpy(&ipAddr.sin_addr, addr, sizeof(struct in_addr));
1641    memcpy(&arpreq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
1642    arpreq.arp_flags= ATF_PUBL;
1643
1644    if (ioctl(sock, SIOCGARP, &arpreq) < 0) {
1645      return -1;
1646    }
1647
1648    memcpy(buf, &arpreq.arp_ha.sa_data[0], len );
1649  }
1650
1651  /*
1652   * All bytes to 0 means no hardware address.
1653   */
1654
1655  for (i = 0; i < len; i++) {
1656    if (buf[i] != 0)
1657      return len;
1658  }
1659
1660  return -1;
1661}
1662
1663static int getMTU(JNIEnv *env, int sock,  const char *ifname) {
1664  struct lifreq if2;
1665
1666  memset((char *) &if2, 0, sizeof(if2));
1667  strcpy(if2.lifr_name, ifname);
1668
1669  if (ioctl(sock, SIOCGLIFMTU, (char *)&if2) < 0) {
1670    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFMTU failed");
1671    return -1;
1672  }
1673
1674  return  if2.lifr_mtu;
1675}
1676
1677
1678static int getFlags(int sock, const char *ifname, int *flags) {
1679  struct   lifreq lifr;
1680  memset((caddr_t)&lifr, 0, sizeof(lifr));
1681  strcpy((caddr_t)&(lifr.lifr_name), ifname);
1682
1683  if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
1684    return -1;
1685  }
1686
1687  *flags = lifr.lifr_flags;
1688  return 0;
1689}
1690
1691
1692#endif
1693
1694
1695/** BSD **/
1696#ifdef _ALLBSD_SOURCE
1697/* Open socket for further ioct calls, try v4 socket first and
1698 * if it falls return v6 socket
1699 */
1700
1701#ifdef AF_INET6
1702static int openSocketWithFallback(JNIEnv *env, const char *ifname){
1703  int sock;
1704  struct ifreq if2;
1705
1706  if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1707    if (errno == EPROTONOSUPPORT){
1708      if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
1709        NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
1710        return -1;
1711      }
1712    }
1713    else{ // errno is not NOSUPPORT
1714      NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
1715      return -1;
1716    }
1717  }
1718
1719  return sock;
1720}
1721
1722#else
1723static int openSocketWithFallback(JNIEnv *env, const char *ifname){
1724  return openSocket(env,AF_INET);
1725}
1726#endif
1727
1728/*
1729 * Enumerates and returns all IPv4 interfaces
1730 */
1731static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
1732  struct ifaddrs *ifa, *origifa;
1733
1734  if (getifaddrs(&origifa) != 0) {
1735    NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException",
1736                                 "getifaddrs() function failed");
1737    return ifs;
1738  }
1739
1740  for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
1741
1742    /*
1743     * Skip non-AF_INET entries.
1744     */
1745    if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)
1746      continue;
1747
1748    /*
1749     * Add to the list.
1750     */
1751    ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, AF_INET, 0);
1752
1753    /*
1754     * If an exception occurred then free the list.
1755     */
1756    if ((*env)->ExceptionOccurred(env)) {
1757      freeifaddrs(origifa);
1758      freeif(ifs);
1759      return NULL;
1760    }
1761  }
1762
1763  /*
1764   * Free socket and buffer
1765   */
1766  freeifaddrs(origifa);
1767  return ifs;
1768}
1769
1770
1771/*
1772 * Enumerates and returns all IPv6 interfaces on Linux
1773 */
1774
1775#ifdef AF_INET6
1776/*
1777 * Determines the prefix on BSD for IPv6 interfaces.
1778 */
1779static
1780int prefix(void *val, int size) {
1781  u_char *name = (u_char *)val;
1782  int byte, bit, plen = 0;
1783
1784  for (byte = 0; byte < size; byte++, plen += 8)
1785    if (name[byte] != 0xff)
1786      break;
1787  if (byte == size)
1788    return (plen);
1789  for (bit = 7; bit != 0; bit--, plen++)
1790    if (!(name[byte] & (1 << bit)))
1791      break;
1792  for (; bit != 0; bit--)
1793    if (name[byte] & (1 << bit))
1794      return (0);
1795  byte++;
1796  for (; byte < size; byte++)
1797    if (name[byte])
1798      return (0);
1799  return (plen);
1800}
1801
1802/*
1803 * Enumerates and returns all IPv6 interfaces on BSD
1804 */
1805static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
1806  struct ifaddrs *ifa, *origifa;
1807  struct sockaddr_in6 *sin6;
1808  struct in6_ifreq ifr6;
1809
1810  if (getifaddrs(&origifa) != 0) {
1811    NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException",
1812                                 "getifaddrs() function failed");
1813    return ifs;
1814  }
1815
1816  for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
1817
1818    /*
1819     * Skip non-AF_INET6 entries.
1820     */
1821    if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET6)
1822      continue;
1823
1824    memset(&ifr6, 0, sizeof(ifr6));
1825    strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
1826    memcpy(&ifr6.ifr_addr, ifa->ifa_addr, MIN(sizeof(ifr6.ifr_addr), ifa->ifa_addr->sa_len));
1827
1828    if (ioctl(sock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0) {
1829      NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException",
1830                                   "ioctl SIOCGIFNETMASK_IN6 failed");
1831      freeifaddrs(origifa);
1832      freeif(ifs);
1833      return NULL;
1834    }
1835
1836    /* Add to the list.  */
1837    sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
1838    ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, AF_INET6,
1839                prefix(&sin6->sin6_addr, sizeof(struct in6_addr)));
1840
1841    /* If an exception occurred then free the list.  */
1842    if ((*env)->ExceptionOccurred(env)) {
1843      freeifaddrs(origifa);
1844      freeif(ifs);
1845      return NULL;
1846    }
1847  }
1848
1849  /*
1850   * Free socket and ifaddrs buffer
1851   */
1852  freeifaddrs(origifa);
1853  return ifs;
1854}
1855#endif
1856
1857static int getIndex(int sock, const char *name){
1858#ifdef __FreeBSD__
1859  /*
1860   * Try to get the interface index
1861   * (Not supported on Solaris 2.6 or 7)
1862   */
1863  struct ifreq if2;
1864  strcpy(if2.ifr_name, name);
1865
1866  if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
1867    return -1;
1868  }
1869
1870  return if2.ifr_index;
1871#else
1872  /*
1873   * Try to get the interface index using BSD specific if_nametoindex
1874   */
1875  int index = if_nametoindex(name);
1876  return (index == 0) ? -1 : index;
1877#endif
1878}
1879
1880/**
1881 * Returns the IPv4 broadcast address of a named interface, if it exists.
1882 * Returns 0 if it doesn't have one.
1883 */
1884static struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) {
1885  struct sockaddr *ret = NULL;
1886  struct ifreq if2;
1887
1888  memset((char *) &if2, 0, sizeof(if2));
1889  strcpy(if2.ifr_name, ifname);
1890
1891  /* Let's make sure the interface does have a broadcast address */
1892  if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
1893    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFFLAGS failed");
1894    return ret;
1895  }
1896
1897  if (if2.ifr_flags & IFF_BROADCAST) {
1898    /* It does, let's retrieve it*/
1899    if (ioctl(sock, SIOCGIFBRDADDR, (char *)&if2) < 0) {
1900      NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFBRDADDR failed");
1901      return ret;
1902    }
1903
1904    ret = brdcast_store;
1905    memcpy(ret, &if2.ifr_broadaddr, sizeof(struct sockaddr));
1906  }
1907
1908  return ret;
1909}
1910
1911/**
1912 * Returns the IPv4 subnet prefix length (aka subnet mask) for the named
1913 * interface, if it has one, otherwise return -1.
1914 */
1915static short getSubnet(JNIEnv *env, int sock, const char *ifname) {
1916  unsigned int mask;
1917  short ret;
1918  struct ifreq if2;
1919
1920  memset((char *) &if2, 0, sizeof(if2));
1921  strcpy(if2.ifr_name, ifname);
1922
1923  if (ioctl(sock, SIOCGIFNETMASK, (char *)&if2) < 0) {
1924    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFNETMASK failed");
1925    return -1;
1926  }
1927
1928  mask = ntohl(((struct sockaddr_in*)&(if2.ifr_addr))->sin_addr.s_addr);
1929  ret = 0;
1930  while (mask) {
1931    mask <<= 1;
1932    ret++;
1933  }
1934
1935  return ret;
1936}
1937
1938/**
1939 * Get the Hardware address (usually MAC address) for the named interface.
1940 * return puts the data in buf, and returns the length, in byte, of the
1941 * MAC address. Returns -1 if there is no hardware address on that interface.
1942 */
1943static int getMacAddress(JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr, unsigned char *buf) {
1944  struct ifaddrs *ifa0, *ifa;
1945  struct sockaddr *saddr;
1946  int i;
1947
1948  /* Grab the interface list */
1949  if (!getifaddrs(&ifa0)) {
1950    /* Cycle through the interfaces */
1951    for (i = 0, ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next, i++) {
1952      saddr = ifa->ifa_addr;
1953      /* Link layer contains the MAC address */
1954      if (saddr->sa_family == AF_LINK && !strcmp(ifname, ifa->ifa_name)) {
1955        struct sockaddr_dl *sadl = (struct sockaddr_dl *) saddr;
1956        /* Check the address is the correct length */
1957        if (sadl->sdl_alen == ETHER_ADDR_LEN) {
1958          memcpy(buf, (sadl->sdl_data + sadl->sdl_nlen), ETHER_ADDR_LEN);
1959          freeifaddrs(ifa0);
1960          return ETHER_ADDR_LEN;
1961        }
1962      }
1963    }
1964    freeifaddrs(ifa0);
1965  }
1966
1967  return -1;
1968}
1969
1970static int getMTU(JNIEnv *env, int sock,  const char *ifname) {
1971  struct ifreq if2;
1972
1973  memset((char *) &if2, 0, sizeof(if2));
1974  strcpy(if2.ifr_name, ifname);
1975
1976  if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
1977    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFMTU failed");
1978    return -1;
1979  }
1980
1981  return  if2.ifr_mtu;
1982}
1983
1984static int getFlags(int sock, const char *ifname, int *flags) {
1985  struct ifreq if2;
1986  int ret = -1;
1987
1988  memset((char *) &if2, 0, sizeof(if2));
1989  strcpy(if2.ifr_name, ifname);
1990
1991  if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0){
1992    return -1;
1993  }
1994
1995  if (sizeof(if2.ifr_flags) == sizeof(short)) {
1996    *flags = (if2.ifr_flags & 0xffff);
1997  } else {
1998    *flags = if2.ifr_flags;
1999  }
2000  return 0;
2001}
2002
2003#endif
2004
2005static JNINativeMethod gMethods[] = {
2006  NATIVE_METHOD(NetworkInterface, getMTU0, "(Ljava/lang/String;I)I"),
2007  NATIVE_METHOD(NetworkInterface, getMacAddr0, "([BLjava/lang/String;I)[B"),
2008  NATIVE_METHOD(NetworkInterface, supportsMulticast0, "(Ljava/lang/String;I)Z"),
2009  NATIVE_METHOD(NetworkInterface, isLoopback0, "(Ljava/lang/String;I)Z"),
2010  NATIVE_METHOD(NetworkInterface, isP2P0, "(Ljava/lang/String;I)Z"),
2011  NATIVE_METHOD(NetworkInterface, isUp0, "(Ljava/lang/String;I)Z"),
2012  NATIVE_METHOD(NetworkInterface, getAll, "()[Ljava/net/NetworkInterface;"),
2013  NATIVE_METHOD(NetworkInterface, getByInetAddress0, "(Ljava/net/InetAddress;)Ljava/net/NetworkInterface;"),
2014  NATIVE_METHOD(NetworkInterface, getByIndex0, "(I)Ljava/net/NetworkInterface;"),
2015  NATIVE_METHOD(NetworkInterface, getByName0, "(Ljava/lang/String;)Ljava/net/NetworkInterface;"),
2016  NATIVE_METHOD(NetworkInterface, init, "()V"),
2017
2018};
2019
2020void register_java_net_NetworkInterface(JNIEnv* env) {
2021  jniRegisterNativeMethods(env, "java/net/NetworkInterface", gMethods, NELEM(gMethods));
2022}
2023