0N/A/*
3909N/A * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
2545N/A
0N/A#include <errno.h>
0N/A#include <strings.h>
4632N/A#if defined(_ALLBSD_SOURCE) && defined(__OpenBSD__)
4632N/A#include <sys/types.h>
4632N/A#endif
0N/A#include <netinet/in.h>
0N/A#include <stdlib.h>
0N/A#include <string.h>
0N/A#include <sys/types.h>
0N/A#include <sys/socket.h>
0N/A#include <arpa/inet.h>
0N/A#include <net/if.h>
0N/A#include <net/if_arp.h>
2545N/A
0N/A#ifdef __solaris__
0N/A#include <sys/dlpi.h>
0N/A#include <fcntl.h>
0N/A#include <stropts.h>
2545N/A#include <sys/sockio.h>
0N/A#endif
2545N/A
0N/A#ifdef __linux__
0N/A#include <sys/ioctl.h>
0N/A#include <bits/ioctls.h>
0N/A#include <sys/utsname.h>
0N/A#include <stdio.h>
0N/A#endif
0N/A
0N/A#ifdef __linux__
0N/A#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
0N/A#endif
0N/A
4632N/A#if defined(_ALLBSD_SOURCE)
4632N/A#include <sys/param.h>
4632N/A#include <sys/ioctl.h>
4632N/A#include <sys/sockio.h>
4632N/A#if defined(__APPLE__)
4632N/A#include <net/ethernet.h>
4632N/A#include <net/if_var.h>
4632N/A#include <net/if_dl.h>
4632N/A#include <netinet/in_var.h>
4632N/A#include <ifaddrs.h>
4632N/A#endif
4632N/A#endif
4632N/A
0N/A#include "jvm.h"
0N/A#include "jni_util.h"
0N/A#include "net_util.h"
0N/A
0N/Atypedef struct _netaddr {
0N/A struct sockaddr *addr;
0N/A struct sockaddr *brdcast;
0N/A short mask;
0N/A int family; /* to make searches simple */
0N/A struct _netaddr *next;
0N/A} netaddr;
0N/A
0N/Atypedef struct _netif {
0N/A char *name;
0N/A int index;
0N/A char virtual;
0N/A netaddr *addr;
0N/A struct _netif *childs;
0N/A struct _netif *next;
0N/A} netif;
0N/A
0N/A/************************************************************************
0N/A * NetworkInterface
0N/A */
0N/A
0N/A#include "java_net_NetworkInterface.h"
0N/A
0N/A/************************************************************************
0N/A * NetworkInterface
0N/A */
0N/Ajclass ni_class;
0N/AjfieldID ni_nameID;
0N/AjfieldID ni_indexID;
0N/AjfieldID ni_descID;
0N/AjfieldID ni_addrsID;
0N/AjfieldID ni_bindsID;
0N/AjfieldID ni_virutalID;
0N/AjfieldID ni_childsID;
0N/AjfieldID ni_parentID;
4638N/AjfieldID ni_defaultIndexID;
0N/AjmethodID ni_ctrID;
0N/A
0N/Astatic jclass ni_iacls;
0N/Astatic jclass ni_ia4cls;
0N/Astatic jclass ni_ia6cls;
0N/Astatic jclass ni_ibcls;
0N/Astatic jmethodID ni_ia4ctrID;
0N/Astatic jmethodID ni_ia6ctrID;
0N/Astatic jmethodID ni_ibctrID;
0N/Astatic jfieldID ni_ia6ipaddressID;
0N/Astatic jfieldID ni_ibaddressID;
0N/Astatic jfieldID ni_ib4broadcastID;
0N/Astatic jfieldID ni_ib4maskID;
0N/A
2545N/A/** Private methods declarations **/
0N/Astatic jobject createNetworkInterface(JNIEnv *env, netif *ifs);
2545N/Astatic int getFlags0(JNIEnv *env, jstring ifname);
0N/A
2545N/Astatic netif *enumInterfaces(JNIEnv *env);
2545N/Astatic netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs);
2545N/A
0N/A#ifdef AF_INET6
2545N/Astatic netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs);
0N/A#endif
0N/A
2545N/Astatic netif *addif(JNIEnv *env, int sock, const char * if_name, netif *ifs, struct sockaddr* ifr_addrP, int family, short prefix);
2545N/Astatic void freeif(netif *ifs);
2545N/A
2545N/Astatic int openSocket(JNIEnv *env, int proto);
2545N/Astatic int openSocketWithFallback(JNIEnv *env, const char *ifname);
2545N/A
2545N/A
2545N/Astatic struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *name, struct sockaddr *brdcast_store);
2545N/Astatic short getSubnet(JNIEnv *env, int sock, const char *ifname);
2578N/Astatic int getIndex(int sock, const char *ifname);
2545N/A
5523N/Astatic int getFlags(int sock, const char *ifname, int *flags);
2545N/Astatic int getMacAddress(JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr, unsigned char *buf);
2545N/Astatic int getMTU(JNIEnv *env, int sock, const char *ifname);
2545N/A
2545N/A
2545N/A
2545N/A#ifdef __solaris__
2545N/Astatic netif *enumIPvXInterfaces(JNIEnv *env, int sock, netif *ifs, int family);
2545N/Astatic int getMacFromDevice(JNIEnv *env, const char* ifname, unsigned char* retbuf);
4501N/A
4501N/A#ifndef SIOCGLIFHWADDR
4501N/A#define SIOCGLIFHWADDR _IOWR('i', 192, struct lifreq)
2545N/A#endif
2545N/A
4501N/A#endif
2545N/A
2545N/A/******************* Java entry points *****************************/
0N/A
0N/A/*
0N/A * Class: java_net_NetworkInterface
0N/A * Method: init
0N/A * Signature: ()V
0N/A */
0N/AJNIEXPORT void JNICALL
0N/AJava_java_net_NetworkInterface_init(JNIEnv *env, jclass cls) {
0N/A ni_class = (*env)->FindClass(env,"java/net/NetworkInterface");
0N/A ni_class = (*env)->NewGlobalRef(env, ni_class);
0N/A ni_nameID = (*env)->GetFieldID(env, ni_class,"name", "Ljava/lang/String;");
0N/A ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");
0N/A ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs", "[Ljava/net/InetAddress;");
0N/A ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings", "[Ljava/net/InterfaceAddress;");
0N/A ni_descID = (*env)->GetFieldID(env, ni_class, "displayName", "Ljava/lang/String;");
0N/A ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z");
0N/A ni_childsID = (*env)->GetFieldID(env, ni_class, "childs", "[Ljava/net/NetworkInterface;");
0N/A ni_parentID = (*env)->GetFieldID(env, ni_class, "parent", "Ljava/net/NetworkInterface;");
0N/A ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");
0N/A
0N/A ni_iacls = (*env)->FindClass(env, "java/net/InetAddress");
0N/A ni_iacls = (*env)->NewGlobalRef(env, ni_iacls);
0N/A ni_ia4cls = (*env)->FindClass(env, "java/net/Inet4Address");
0N/A ni_ia4cls = (*env)->NewGlobalRef(env, ni_ia4cls);
0N/A ni_ia6cls = (*env)->FindClass(env, "java/net/Inet6Address");
0N/A ni_ia6cls = (*env)->NewGlobalRef(env, ni_ia6cls);
0N/A ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");
0N/A ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);
0N/A ni_ia4ctrID = (*env)->GetMethodID(env, ni_ia4cls, "<init>", "()V");
0N/A ni_ia6ctrID = (*env)->GetMethodID(env, ni_ia6cls, "<init>", "()V");
0N/A ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");
0N/A ni_ia6ipaddressID = (*env)->GetFieldID(env, ni_ia6cls, "ipaddress", "[B");
0N/A ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address", "Ljava/net/InetAddress;");
0N/A ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast", "Ljava/net/Inet4Address;");
0N/A ni_ib4maskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");
4638N/A ni_defaultIndexID = (*env)->GetStaticFieldID(env, ni_class, "defaultIndex", "I");
0N/A}
0N/A
0N/A
0N/A/*
0N/A * Class: java_net_NetworkInterface
0N/A * Method: getByName0
0N/A * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
0N/A */
0N/AJNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0
0N/A (JNIEnv *env, jclass cls, jstring name) {
0N/A
0N/A netif *ifs, *curr;
0N/A jboolean isCopy;
2545N/A const char* name_utf;
0N/A jobject obj = NULL;
0N/A
0N/A ifs = enumInterfaces(env);
0N/A if (ifs == NULL) {
0N/A return NULL;
0N/A }
0N/A
2545N/A name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
2545N/A
0N/A /*
0N/A * Search the list of interface based on name
0N/A */
0N/A curr = ifs;
0N/A while (curr != NULL) {
0N/A if (strcmp(name_utf, curr->name) == 0) {
0N/A break;
0N/A }
0N/A curr = curr->next;
0N/A }
0N/A
0N/A /* if found create a NetworkInterface */
0N/A if (curr != NULL) {;
0N/A obj = createNetworkInterface(env, curr);
0N/A }
0N/A
0N/A /* release the UTF string and interface list */
0N/A (*env)->ReleaseStringUTFChars(env, name, name_utf);
0N/A freeif(ifs);
0N/A
0N/A return obj;
0N/A}
0N/A
0N/A
0N/A/*
0N/A * Class: java_net_NetworkInterface
509N/A * Method: getByIndex0
0N/A * Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;
0N/A */
509N/AJNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0
0N/A (JNIEnv *env, jclass cls, jint index) {
0N/A
0N/A netif *ifs, *curr;
0N/A jobject obj = NULL;
0N/A
0N/A if (index <= 0) {
0N/A return NULL;
0N/A }
0N/A
0N/A ifs = enumInterfaces(env);
0N/A if (ifs == NULL) {
0N/A return NULL;
0N/A }
0N/A
0N/A /*
0N/A * Search the list of interface based on index
0N/A */
0N/A curr = ifs;
0N/A while (curr != NULL) {
0N/A if (index == curr->index) {
0N/A break;
0N/A }
0N/A curr = curr->next;
0N/A }
0N/A
0N/A /* if found create a NetworkInterface */
0N/A if (curr != NULL) {;
0N/A obj = createNetworkInterface(env, curr);
0N/A }
0N/A
0N/A freeif(ifs);
0N/A return obj;
0N/A}
0N/A
0N/A/*
0N/A * Class: java_net_NetworkInterface
0N/A * Method: getByInetAddress0
0N/A * Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
0N/A */
0N/AJNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
0N/A (JNIEnv *env, jclass cls, jobject iaObj) {
0N/A
0N/A netif *ifs, *curr;
2545N/A
2112N/A#ifdef AF_INET6
5888N/A int family = (getInetAddress_family(env, iaObj) == IPv4) ? AF_INET : AF_INET6;
2112N/A#else
2545N/A int family = AF_INET;
2112N/A#endif
2545N/A
0N/A jobject obj = NULL;
0N/A jboolean match = JNI_FALSE;
0N/A
0N/A ifs = enumInterfaces(env);
0N/A if (ifs == NULL) {
0N/A return NULL;
0N/A }
0N/A
0N/A curr = ifs;
0N/A while (curr != NULL) {
0N/A netaddr *addrP = curr->addr;
0N/A
0N/A /*
0N/A * Iterate through each address on the interface
0N/A */
0N/A while (addrP != NULL) {
0N/A
0N/A if (family == addrP->family) {
0N/A if (family == AF_INET) {
0N/A int address1 = htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr);
5888N/A int address2 = getInetAddress_addr(env, iaObj);
0N/A
0N/A if (address1 == address2) {
0N/A match = JNI_TRUE;
0N/A break;
0N/A }
0N/A }
0N/A
0N/A#ifdef AF_INET6
0N/A if (family == AF_INET6) {
0N/A jbyte *bytes = (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr);
0N/A jbyteArray ipaddress = (*env)->GetObjectField(env, iaObj, ni_ia6ipaddressID);
0N/A jbyte caddr[16];
0N/A int i;
0N/A
0N/A (*env)->GetByteArrayRegion(env, ipaddress, 0, 16, caddr);
0N/A i = 0;
0N/A while (i < 16) {
0N/A if (caddr[i] != bytes[i]) {
0N/A break;
0N/A }
0N/A i++;
0N/A }
0N/A if (i >= 16) {
0N/A match = JNI_TRUE;
0N/A break;
0N/A }
0N/A }
0N/A#endif
0N/A
0N/A }
0N/A
0N/A if (match) {
0N/A break;
0N/A }
0N/A addrP = addrP->next;
0N/A }
0N/A
0N/A if (match) {
0N/A break;
0N/A }
0N/A curr = curr->next;
0N/A }
0N/A
0N/A /* if found create a NetworkInterface */
0N/A if (match) {;
0N/A obj = createNetworkInterface(env, curr);
0N/A }
0N/A
0N/A freeif(ifs);
0N/A return obj;
0N/A}
0N/A
0N/A
0N/A/*
0N/A * Class: java_net_NetworkInterface
0N/A * Method: getAll
0N/A * Signature: ()[Ljava/net/NetworkInterface;
0N/A */
0N/AJNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll
0N/A (JNIEnv *env, jclass cls) {
0N/A
0N/A netif *ifs, *curr;
0N/A jobjectArray netIFArr;
0N/A jint arr_index, ifCount;
0N/A
0N/A ifs = enumInterfaces(env);
0N/A if (ifs == NULL) {
0N/A return NULL;
0N/A }
0N/A
0N/A /* count the interface */
0N/A ifCount = 0;
0N/A curr = ifs;
0N/A while (curr != NULL) {
0N/A ifCount++;
0N/A curr = curr->next;
0N/A }
0N/A
0N/A /* allocate a NetworkInterface array */
0N/A netIFArr = (*env)->NewObjectArray(env, ifCount, cls, NULL);
0N/A if (netIFArr == NULL) {
0N/A freeif(ifs);
0N/A return NULL;
0N/A }
0N/A
0N/A /*
0N/A * Iterate through the interfaces, create a NetworkInterface instance
0N/A * for each array element and populate the object.
0N/A */
0N/A curr = ifs;
0N/A arr_index = 0;
0N/A while (curr != NULL) {
0N/A jobject netifObj;
0N/A
0N/A netifObj = createNetworkInterface(env, curr);
0N/A if (netifObj == NULL) {
0N/A freeif(ifs);
0N/A return NULL;
0N/A }
0N/A
0N/A /* put the NetworkInterface into the array */
0N/A (*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);
0N/A
0N/A curr = curr->next;
0N/A }
0N/A
0N/A freeif(ifs);
0N/A return netIFArr;
0N/A}
0N/A
2545N/A
2545N/A/*
2545N/A * Class: java_net_NetworkInterface
2545N/A * Method: isUp0
2545N/A * Signature: (Ljava/lang/String;I)Z
2545N/A */
2545N/AJNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0(JNIEnv *env, jclass cls, jstring name, jint index) {
2545N/A int ret = getFlags0(env, name);
2545N/A return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE : JNI_FALSE;
2545N/A}
2545N/A
2545N/A/*
2545N/A * Class: java_net_NetworkInterface
2545N/A * Method: isP2P0
2545N/A * Signature: (Ljava/lang/String;I)Z
2545N/A */
2545N/AJNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0(JNIEnv *env, jclass cls, jstring name, jint index) {
2545N/A int ret = getFlags0(env, name);
2545N/A return (ret & IFF_POINTOPOINT) ? JNI_TRUE : JNI_FALSE;
2545N/A}
2545N/A
2545N/A/*
2545N/A * Class: java_net_NetworkInterface
2545N/A * Method: isLoopback0
2545N/A * Signature: (Ljava/lang/String;I)Z
2545N/A */
2545N/AJNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0(JNIEnv *env, jclass cls, jstring name, jint index) {
2545N/A int ret = getFlags0(env, name);
2545N/A return (ret & IFF_LOOPBACK) ? JNI_TRUE : JNI_FALSE;
2545N/A}
2545N/A
2545N/A/*
2545N/A * Class: java_net_NetworkInterface
2545N/A * Method: supportsMulticast0
2545N/A * Signature: (Ljava/lang/String;I)Z
2545N/A */
2545N/AJNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0(JNIEnv *env, jclass cls, jstring name, jint index) {
2545N/A int ret = getFlags0(env, name);
2545N/A return (ret & IFF_MULTICAST) ? JNI_TRUE : JNI_FALSE;
2545N/A}
2545N/A
2545N/A/*
2545N/A * Class: java_net_NetworkInterface
2545N/A * Method: getMacAddr0
2545N/A * Signature: ([bLjava/lang/String;I)[b
2545N/A */
2545N/AJNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0(JNIEnv *env, jclass class, jbyteArray addrArray, jstring name, jint index) {
2545N/A jint addr;
2545N/A jbyte caddr[4];
2545N/A struct in_addr iaddr;
2545N/A jbyteArray ret = NULL;
2545N/A unsigned char mac[16];
2545N/A int len;
2545N/A int sock;
2545N/A jboolean isCopy;
2545N/A const char* name_utf;
2545N/A
2545N/A name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
2545N/A
2545N/A if ((sock =openSocketWithFallback(env, name_utf)) < 0) {
2545N/A (*env)->ReleaseStringUTFChars(env, name, name_utf);
2545N/A return JNI_FALSE;
2545N/A }
2545N/A
2545N/A
2545N/A if (!IS_NULL(addrArray)) {
2545N/A (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
2545N/A addr = ((caddr[0]<<24) & 0xff000000);
2545N/A addr |= ((caddr[1] <<16) & 0xff0000);
2545N/A addr |= ((caddr[2] <<8) & 0xff00);
2545N/A addr |= (caddr[3] & 0xff);
2545N/A iaddr.s_addr = htonl(addr);
2545N/A len = getMacAddress(env, sock, name_utf, &iaddr, mac);
2545N/A } else {
2545N/A len = getMacAddress(env, sock, name_utf,NULL, mac);
2545N/A }
2545N/A if (len > 0) {
2545N/A ret = (*env)->NewByteArray(env, len);
2545N/A if (IS_NULL(ret)) {
2545N/A /* we may have memory to free at the end of this */
2545N/A goto fexit;
2545N/A }
2545N/A (*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *) (mac));
2545N/A }
2545N/A fexit:
2545N/A /* release the UTF string and interface list */
2545N/A (*env)->ReleaseStringUTFChars(env, name, name_utf);
2545N/A
2545N/A close(sock);
2545N/A return ret;
2545N/A}
2545N/A
2545N/A/*
2545N/A * Class: java_net_NetworkInterface
2545N/A * Method: getMTU0
2545N/A * Signature: ([bLjava/lang/String;I)I
2545N/A */
2545N/A
2545N/AJNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0(JNIEnv *env, jclass class, jstring name, jint index) {
2545N/A jboolean isCopy;
2545N/A int ret = -1;
2545N/A int sock;
2545N/A const char* name_utf;
2545N/A
2545N/A name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
2545N/A
2545N/A if ((sock =openSocketWithFallback(env, name_utf)) < 0) {
2545N/A (*env)->ReleaseStringUTFChars(env, name, name_utf);
2545N/A return JNI_FALSE;
2545N/A }
2545N/A
2545N/A ret = getMTU(env, sock, name_utf);
2545N/A
2545N/A (*env)->ReleaseStringUTFChars(env, name, name_utf);
2545N/A
2545N/A close(sock);
2545N/A return ret;
2545N/A}
2545N/A
2545N/A/*** Private methods definitions ****/
2545N/A
2545N/Astatic int getFlags0(JNIEnv *env, jstring name) {
2545N/A jboolean isCopy;
2545N/A int ret, sock;
2545N/A const char* name_utf;
5523N/A int flags = 0;
2545N/A
2545N/A name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
2545N/A
2545N/A if ((sock = openSocketWithFallback(env, name_utf)) < 0) {
2545N/A (*env)->ReleaseStringUTFChars(env, name, name_utf);
2545N/A return -1;
2545N/A }
2545N/A
2545N/A name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);
2545N/A
5523N/A ret = getFlags(sock, name_utf, &flags);
2545N/A
2545N/A close(sock);
2545N/A (*env)->ReleaseStringUTFChars(env, name, name_utf);
2545N/A
2545N/A if (ret < 0) {
2545N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFFLAGS failed");
2545N/A return -1;
2545N/A }
2545N/A
5523N/A return flags;
2545N/A}
2545N/A
2545N/A
2545N/A
2545N/A
0N/A/*
0N/A * Create a NetworkInterface object, populate the name and index, and
0N/A * populate the InetAddress array based on the IP addresses for this
0N/A * interface.
0N/A */
2545N/Ajobject createNetworkInterface(JNIEnv *env, netif *ifs) {
0N/A jobject netifObj;
0N/A jobject name;
0N/A jobjectArray addrArr;
0N/A jobjectArray bindArr;
0N/A jobjectArray childArr;
2545N/A netaddr *addrs;
0N/A jint addr_index, addr_count, bind_index;
0N/A jint child_count, child_index;
0N/A netaddr *addrP;
0N/A netif *childP;
0N/A jobject tmp;
0N/A
0N/A /*
0N/A * Create a NetworkInterface object and populate it
0N/A */
0N/A netifObj = (*env)->NewObject(env, ni_class, ni_ctrID);
0N/A name = (*env)->NewStringUTF(env, ifs->name);
0N/A if (netifObj == NULL || name == NULL) {
0N/A return NULL;
0N/A }
0N/A (*env)->SetObjectField(env, netifObj, ni_nameID, name);
0N/A (*env)->SetObjectField(env, netifObj, ni_descID, name);
0N/A (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
0N/A (*env)->SetBooleanField(env, netifObj, ni_virutalID, ifs->virtual ? JNI_TRUE : JNI_FALSE);
0N/A
0N/A /*
0N/A * Count the number of address on this interface
0N/A */
0N/A addr_count = 0;
0N/A addrP = ifs->addr;
0N/A while (addrP != NULL) {
0N/A addr_count++;
0N/A addrP = addrP->next;
0N/A }
0N/A
0N/A /*
0N/A * Create the array of InetAddresses
0N/A */
0N/A addrArr = (*env)->NewObjectArray(env, addr_count, ni_iacls, NULL);
0N/A if (addrArr == NULL) {
0N/A return NULL;
0N/A }
0N/A
0N/A bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL);
0N/A if (bindArr == NULL) {
2545N/A return NULL;
0N/A }
0N/A addrP = ifs->addr;
0N/A addr_index = 0;
0N/A bind_index = 0;
0N/A while (addrP != NULL) {
0N/A jobject iaObj = NULL;
0N/A jobject ibObj = NULL;
0N/A
0N/A if (addrP->family == AF_INET) {
0N/A iaObj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
0N/A if (iaObj) {
5888N/A setInetAddress_addr(env, iaObj, htonl(((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr));
0N/A }
0N/A ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
0N/A if (ibObj) {
2545N/A (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
2545N/A if (addrP->brdcast) {
2545N/A jobject ia2Obj = NULL;
2545N/A ia2Obj = (*env)->NewObject(env, ni_ia4cls, ni_ia4ctrID);
2545N/A if (ia2Obj) {
5888N/A setInetAddress_addr(env, ia2Obj, htonl(((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr));
2545N/A (*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj);
2545N/A (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
2545N/A }
2545N/A }
2545N/A (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
0N/A }
0N/A }
0N/A
0N/A#ifdef AF_INET6
0N/A if (addrP->family == AF_INET6) {
0N/A int scope=0;
0N/A iaObj = (*env)->NewObject(env, ni_ia6cls, ni_ia6ctrID);
0N/A if (iaObj) {
0N/A jbyteArray ipaddress = (*env)->NewByteArray(env, 16);
0N/A if (ipaddress == NULL) {
0N/A return NULL;
0N/A }
0N/A (*env)->SetByteArrayRegion(env, ipaddress, 0, 16,
2545N/A (jbyte *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr));
2545N/A
0N/A scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;
2545N/A
0N/A if (scope != 0) { /* zero is default value, no need to set */
0N/A (*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
0N/A (*env)->SetBooleanField(env, iaObj, ia6_scopeidsetID, JNI_TRUE);
0N/A (*env)->SetObjectField(env, iaObj, ia6_scopeifnameID, netifObj);
0N/A }
0N/A (*env)->SetObjectField(env, iaObj, ni_ia6ipaddressID, ipaddress);
0N/A }
0N/A ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
0N/A if (ibObj) {
2545N/A (*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
2545N/A (*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);
2545N/A (*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);
0N/A }
0N/A }
0N/A#endif
0N/A
0N/A if (iaObj == NULL) {
0N/A return NULL;
0N/A }
0N/A
0N/A (*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj);
0N/A addrP = addrP->next;
0N/A }
0N/A
0N/A /*
0N/A * See if there is any virtual interface attached to this one.
0N/A */
0N/A child_count = 0;
0N/A childP = ifs->childs;
0N/A while (childP) {
2545N/A child_count++;
2545N/A childP = childP->next;
0N/A }
0N/A
0N/A childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL);
0N/A if (childArr == NULL) {
2545N/A return NULL;
0N/A }
0N/A
0N/A /*
0N/A * Create the NetworkInterface instances for the sub-interfaces as
0N/A * well.
0N/A */
0N/A child_index = 0;
0N/A childP = ifs->childs;
0N/A while(childP) {
0N/A tmp = createNetworkInterface(env, childP);
0N/A if (tmp == NULL) {
2545N/A return NULL;
0N/A }
0N/A (*env)->SetObjectField(env, tmp, ni_parentID, netifObj);
0N/A (*env)->SetObjectArrayElement(env, childArr, child_index++, tmp);
0N/A childP = childP->next;
0N/A }
0N/A (*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
0N/A (*env)->SetObjectField(env, netifObj, ni_bindsID, bindArr);
0N/A (*env)->SetObjectField(env, netifObj, ni_childsID, childArr);
0N/A
0N/A /* return the NetworkInterface */
0N/A return netifObj;
0N/A}
0N/A
0N/A/*
0N/A * Enumerates all interfaces
0N/A */
0N/Astatic netif *enumInterfaces(JNIEnv *env) {
0N/A netif *ifs;
2545N/A int sock;
0N/A
0N/A /*
0N/A * Enumerate IPv4 addresses
0N/A */
2545N/A
2545N/A sock = openSocket(env, AF_INET);
2545N/A if (sock < 0 && (*env)->ExceptionOccurred(env)) {
2545N/A return NULL;
0N/A }
0N/A
2545N/A ifs = enumIPv4Interfaces(env, sock, NULL);
2545N/A close(sock);
2545N/A
2545N/A if (ifs == NULL && (*env)->ExceptionOccurred(env)) {
2545N/A return NULL;
2545N/A }
2545N/A
2545N/A /* return partial list if exception occure in the middle of process ???*/
2545N/A
0N/A /*
0N/A * If IPv6 is available then enumerate IPv6 addresses.
0N/A */
0N/A#ifdef AF_INET6
2605N/A
2605N/A /* User can disable ipv6 expicitly by -Djava.net.preferIPv4Stack=true,
2605N/A * so we have to call ipv6_available()
2605N/A */
2605N/A if (ipv6_available()) {
2545N/A
2605N/A sock = openSocket(env, AF_INET6);
2605N/A if (sock < 0 && (*env)->ExceptionOccurred(env)) {
2605N/A freeif(ifs);
2605N/A return NULL;
2605N/A }
0N/A
2605N/A ifs = enumIPv6Interfaces(env, sock, ifs);
2605N/A close(sock);
2605N/A
2605N/A if ((*env)->ExceptionOccurred(env)) {
2605N/A freeif(ifs);
2605N/A return NULL;
2605N/A }
2605N/A
2605N/A }
0N/A#endif
0N/A
0N/A return ifs;
0N/A}
0N/A
2545N/A#define CHECKED_MALLOC3(_pointer,_type,_size) \
2545N/A do{ \
2545N/A _pointer = (_type)malloc( _size ); \
2545N/A if (_pointer == NULL) { \
5476N/A JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \
2545N/A return ifs; /* return untouched list */ \
2545N/A } \
2545N/A } while(0)
0N/A
0N/A
0N/A/*
0N/A * Free an interface list (including any attached addresses)
0N/A */
0N/Avoid freeif(netif *ifs) {
0N/A netif *currif = ifs;
2545N/A netif *child = NULL;
0N/A
0N/A while (currif != NULL) {
0N/A netaddr *addrP = currif->addr;
0N/A while (addrP != NULL) {
0N/A netaddr *next = addrP->next;
0N/A free(addrP);
0N/A addrP = next;
2545N/A }
0N/A
2545N/A /*
2545N/A * Don't forget to free the sub-interfaces.
2545N/A */
2545N/A if (currif->childs != NULL) {
2545N/A freeif(currif->childs);
2545N/A }
0N/A
2545N/A ifs = currif->next;
2545N/A free(currif);
2545N/A currif = ifs;
0N/A }
0N/A}
0N/A
6071N/Anetif *addif(JNIEnv *env, int sock, const char * if_name,
6071N/A netif *ifs, struct sockaddr* ifr_addrP, int family,
6071N/A short prefix)
6071N/A{
2545N/A netif *currif = ifs, *parent;
0N/A netaddr *addrP;
2545N/A
4632N/A#ifdef LIFNAMSIZ
6071N/A int ifnam_size = LIFNAMSIZ;
6071N/A char name[LIFNAMSIZ], vname[LIFNAMSIZ];
4632N/A#else
6071N/A int ifnam_size = IFNAMSIZ;
6071N/A char name[IFNAMSIZ], vname[IFNAMSIZ];
4632N/A#endif
2545N/A
2545N/A char *name_colonP;
2545N/A int mask;
0N/A int isVirtual = 0;
2545N/A int addr_size;
5523N/A int flags = 0;
0N/A
0N/A /*
0N/A * If the interface name is a logical interface then we
0N/A * remove the unit number so that we have the physical
0N/A * interface (eg: hme0:1 -> hme0). NetworkInterface
0N/A * currently doesn't have any concept of physical vs.
0N/A * logical interfaces.
0N/A */
6071N/A strncpy(name, if_name, ifnam_size);
6071N/A name[ifnam_size - 1] = '\0';
2545N/A *vname = 0;
0N/A
0N/A /*
0N/A * Create and populate the netaddr node. If allocation fails
0N/A * return an un-updated list.
0N/A */
2545N/A /*Allocate for addr and brdcast at once*/
2545N/A
2545N/A#ifdef AF_INET6
2545N/A addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
2545N/A#else
2545N/A addr_size = sizeof(struct sockaddr_in);
2545N/A#endif
2545N/A
2545N/A CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr)+2*addr_size);
2545N/A addrP->addr = (struct sockaddr *)( (char *) addrP+sizeof(netaddr) );
2545N/A memcpy(addrP->addr, ifr_addrP, addr_size);
2545N/A
0N/A addrP->family = family;
0N/A addrP->brdcast = NULL;
0N/A addrP->mask = prefix;
2545N/A addrP->next = 0;
0N/A if (family == AF_INET) {
0N/A /*
0N/A * Deal with brodcast addr & subnet mask
0N/A */
2545N/A struct sockaddr * brdcast_to = (struct sockaddr *) ((char *) addrP + sizeof(netaddr) + addr_size);
2545N/A addrP->brdcast = getBroadcast(env, sock, name, brdcast_to );
0N/A
2545N/A if (addrP->brdcast && (mask = getSubnet(env, sock, name)) != -1) {
2545N/A addrP->mask = mask;
2545N/A }
2545N/A }
2545N/A
2545N/A /**
2545N/A * Deal with virtual interface with colon notaion e.g. eth0:1
2545N/A */
2545N/A name_colonP = strchr(name, ':');
2545N/A if (name_colonP != NULL) {
0N/A /**
0N/A * This is a virtual interface. If we are able to access the parent
0N/A * we need to create a new entry if it doesn't exist yet *and* update
0N/A * the 'parent' interface with the new records.
0N/A */
2545N/A *name_colonP = 0;
5523N/A if (getFlags(sock, name, &flags) < 0 || flags < 0) {
894N/A // failed to access parent interface do not create parent.
894N/A // We are a virtual interface with no parent.
894N/A isVirtual = 1;
2545N/A *name_colonP = ':';
0N/A }
2545N/A else{
2545N/A // Got access to parent, so create it if necessary.
2545N/A // Save original name to vname and truncate name by ':'
2545N/A memcpy(vname, name, sizeof(vname) );
2545N/A vname[name_colonP - name] = ':';
2545N/A }
0N/A }
0N/A
0N/A /*
0N/A * Check if this is a "new" interface. Use the interface
0N/A * name for matching because index isn't supported on
0N/A * Solaris 2.6 & 7.
0N/A */
0N/A while (currif != NULL) {
0N/A if (strcmp(name, currif->name) == 0) {
0N/A break;
0N/A }
0N/A currif = currif->next;
0N/A }
0N/A
0N/A /*
0N/A * If "new" then create an netif structure and
0N/A * insert it onto the list.
0N/A */
0N/A if (currif == NULL) {
6071N/A CHECKED_MALLOC3(currif, netif *, sizeof(netif) + ifnam_size);
2545N/A currif->name = (char *) currif+sizeof(netif);
6071N/A strncpy(currif->name, name, ifnam_size);
6071N/A currif->name[ifnam_size - 1] = '\0';
2578N/A currif->index = getIndex(sock, name);
2545N/A currif->addr = NULL;
2545N/A currif->childs = NULL;
2545N/A currif->virtual = isVirtual;
2545N/A currif->next = ifs;
2545N/A ifs = currif;
0N/A }
0N/A
0N/A /*
0N/A * Finally insert the address on the interface
0N/A */
0N/A addrP->next = currif->addr;
0N/A currif->addr = addrP;
0N/A
0N/A parent = currif;
0N/A
0N/A /**
0N/A * Let's deal with the virtual interface now.
0N/A */
0N/A if (vname[0]) {
2545N/A netaddr *tmpaddr;
0N/A
2545N/A currif = parent->childs;
0N/A
2545N/A while (currif != NULL) {
2545N/A if (strcmp(vname, currif->name) == 0) {
2545N/A break;
2545N/A }
2545N/A currif = currif->next;
0N/A }
2545N/A
2545N/A if (currif == NULL) {
6071N/A CHECKED_MALLOC3(currif, netif *, sizeof(netif) + ifnam_size);
2545N/A currif->name = (char *) currif + sizeof(netif);
6071N/A strncpy(currif->name, vname, ifnam_size);
6071N/A currif->name[ifnam_size - 1] = '\0';
2578N/A currif->index = getIndex(sock, vname);
2545N/A currif->addr = NULL;
2545N/A /* Need to duplicate the addr entry? */
2545N/A currif->virtual = 1;
2545N/A currif->childs = NULL;
2545N/A currif->next = parent->childs;
2545N/A parent->childs = currif;
2545N/A }
0N/A
2545N/A CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr)+2*addr_size);
2545N/A memcpy(tmpaddr, addrP, sizeof(netaddr));
2545N/A if (addrP->addr != NULL) {
2545N/A tmpaddr->addr = (struct sockaddr *) ( (char*)tmpaddr + sizeof(netaddr) ) ;
2545N/A memcpy(tmpaddr->addr, addrP->addr, addr_size);
2545N/A }
2545N/A
2545N/A if (addrP->brdcast != NULL) {
2545N/A tmpaddr->brdcast = (struct sockaddr *) ((char *) tmpaddr + sizeof(netaddr)+addr_size);
2545N/A memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size);
2545N/A }
2545N/A
2545N/A tmpaddr->next = currif->addr;
2545N/A currif->addr = tmpaddr;
0N/A }
0N/A
0N/A return ifs;
0N/A}
0N/A
2545N/A/* Open socket for further ioct calls
2545N/A * proto is AF_INET/AF_INET6
0N/A */
2545N/Astatic int openSocket(JNIEnv *env, int proto){
2545N/A int sock;
2545N/A
2545N/A if ((sock = JVM_Socket(proto, SOCK_DGRAM, 0)) < 0) {
2545N/A /*
2545N/A * If EPROTONOSUPPORT is returned it means we don't have
2545N/A * support for this proto so don't throw an exception.
2545N/A */
2545N/A if (errno != EPROTONOSUPPORT) {
2545N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "Socket creation failed");
2545N/A }
2545N/A return -1;
2545N/A }
0N/A
2545N/A return sock;
2545N/A}
2545N/A
2545N/A
2545N/A/** Linux **/
2545N/A#ifdef __linux__
2545N/A/* Open socket for further ioct calls, try v4 socket first and
2545N/A * if it falls return v6 socket
2545N/A */
2545N/A
2545N/A#ifdef AF_INET6
2545N/Astatic int openSocketWithFallback(JNIEnv *env, const char *ifname){
2545N/A int sock;
2545N/A struct ifreq if2;
0N/A
2545N/A if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
2545N/A if (errno == EPROTONOSUPPORT){
2545N/A if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
2545N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
2545N/A return -1;
2545N/A }
2545N/A }
2545N/A else{ // errno is not NOSUPPORT
2545N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
2545N/A return -1;
2545N/A }
2545N/A }
2545N/A
2545N/A /* Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or IPv6 socket regardless of type
2545N/A of address of an interface */
2545N/A
2545N/A return sock;
2545N/A}
2545N/A
2545N/A#else
2545N/Astatic int openSocketWithFallback(JNIEnv *env, const char *ifname){
2545N/A return openSocket(env,AF_INET);
2545N/A}
2545N/A#endif
0N/A
2545N/Astatic netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
2545N/A struct ifconf ifc;
2545N/A struct ifreq *ifreqP;
2545N/A char *buf;
2545N/A int numifs;
2545N/A unsigned i;
2545N/A
375N/A
2545N/A /* need to do a dummy SIOCGIFCONF to determine the buffer size.
2545N/A * SIOCGIFCOUNT doesn't work
2545N/A */
2545N/A ifc.ifc_buf = NULL;
2545N/A if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
2545N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGIFCONF failed");
2545N/A return ifs;
2545N/A }
375N/A
2545N/A CHECKED_MALLOC3(buf,char *, ifc.ifc_len);
2545N/A
2545N/A ifc.ifc_buf = buf;
2545N/A if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
2545N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGIFCONF failed");
2545N/A (void) free(buf);
2545N/A return ifs;
375N/A }
375N/A
2545N/A /*
2545N/A * Iterate through each interface
2545N/A */
2545N/A ifreqP = ifc.ifc_req;
2545N/A for (i=0; i<ifc.ifc_len/sizeof (struct ifreq); i++, ifreqP++) {
2545N/A /*
2545N/A * Add to the list
2545N/A */
2545N/A ifs = addif(env, sock, ifreqP->ifr_name, ifs, (struct sockaddr *) & (ifreqP->ifr_addr), AF_INET, 0);
375N/A
2545N/A /*
2545N/A * If an exception occurred then free the list
2545N/A */
2545N/A if ((*env)->ExceptionOccurred(env)) {
2545N/A free(buf);
2545N/A freeif(ifs);
2545N/A return NULL;
2545N/A }
375N/A }
2545N/A
2545N/A /*
2545N/A * Free socket and buffer
2545N/A */
2545N/A free(buf);
2545N/A return ifs;
2545N/A}
2545N/A
2545N/A
2545N/A/*
2545N/A * Enumerates and returns all IPv6 interfaces on Linux
2545N/A */
2545N/A
2545N/A#ifdef AF_INET6
2545N/Astatic netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
2545N/A FILE *f;
3657N/A char addr6[40], devname[21];
2545N/A char addr6p[8][5];
2545N/A int plen, scope, dad_status, if_idx;
2545N/A uint8_t ipv6addr[16];
2545N/A
2545N/A if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
5826N/A while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
2545N/A addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7],
2545N/A &if_idx, &plen, &scope, &dad_status, devname) != EOF) {
2545N/A
2545N/A struct netif *ifs_ptr = NULL;
2545N/A struct netif *last_ptr = NULL;
2545N/A struct sockaddr_in6 addr;
2545N/A
2545N/A sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
2545N/A addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
2545N/A inet_pton(AF_INET6, addr6, ipv6addr);
2545N/A
2545N/A memset(&addr, 0, sizeof(struct sockaddr_in6));
2545N/A memcpy((void*)addr.sin6_addr.s6_addr, (const void*)ipv6addr, 16);
2545N/A
2545N/A addr.sin6_scope_id = if_idx;
2545N/A
2545N/A ifs = addif(env, sock, devname, ifs, (struct sockaddr *)&addr, AF_INET6, plen);
2545N/A
2545N/A
2545N/A /*
2545N/A * If an exception occurred then return the list as is.
2545N/A */
2545N/A if ((*env)->ExceptionOccurred(env)) {
2545N/A fclose(f);
2545N/A return ifs;
2545N/A }
2545N/A }
2545N/A fclose(f);
2545N/A }
2545N/A return ifs;
2545N/A}
375N/A#endif
2545N/A
0N/A
2578N/Astatic int getIndex(int sock, const char *name){
2545N/A /*
2545N/A * Try to get the interface index
2545N/A * (Not supported on Solaris 2.6 or 7)
2545N/A */
2545N/A struct ifreq if2;
2545N/A strcpy(if2.ifr_name, name);
2545N/A
2545N/A if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
2545N/A return -1;
2545N/A }
2545N/A
2545N/A return if2.ifr_ifindex;
0N/A}
0N/A
0N/A/**
0N/A * Returns the IPv4 broadcast address of a named interface, if it exists.
0N/A * Returns 0 if it doesn't have one.
0N/A */
2545N/Astatic struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) {
0N/A struct sockaddr *ret = NULL;
0N/A struct ifreq if2;
0N/A
0N/A memset((char *) &if2, 0, sizeof(if2));
0N/A strcpy(if2.ifr_name, ifname);
2545N/A
0N/A /* Let's make sure the interface does have a broadcast address */
2545N/A if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
2545N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFFLAGS failed");
2545N/A return ret;
0N/A }
2545N/A
2545N/A if (if2.ifr_flags & IFF_BROADCAST) {
2545N/A /* It does, let's retrieve it*/
2545N/A if (ioctl(sock, SIOCGIFBRDADDR, (char *)&if2) < 0) {
2545N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFBRDADDR failed");
2545N/A return ret;
2545N/A }
2545N/A
2545N/A ret = brdcast_store;
0N/A memcpy(ret, &if2.ifr_broadaddr, sizeof(struct sockaddr));
0N/A }
2545N/A
0N/A return ret;
0N/A}
0N/A
0N/A/**
0N/A * Returns the IPv4 subnet prefix length (aka subnet mask) for the named
0N/A * interface, if it has one, otherwise return -1.
0N/A */
2545N/Astatic short getSubnet(JNIEnv *env, int sock, const char *ifname) {
2545N/A unsigned int mask;
2545N/A short ret;
2545N/A struct ifreq if2;
2545N/A
2545N/A memset((char *) &if2, 0, sizeof(if2));
2545N/A strcpy(if2.ifr_name, ifname);
2545N/A
2545N/A if (ioctl(sock, SIOCGIFNETMASK, (char *)&if2) < 0) {
2545N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFNETMASK failed");
2545N/A return -1;
2545N/A }
2545N/A
2545N/A mask = ntohl(((struct sockaddr_in*)&(if2.ifr_addr))->sin_addr.s_addr);
2545N/A ret = 0;
2545N/A while (mask) {
2545N/A mask <<= 1;
2545N/A ret++;
2545N/A }
2545N/A
2545N/A return ret;
2545N/A}
2545N/A
2545N/A/**
2545N/A * Get the Hardware address (usually MAC address) for the named interface.
2545N/A * return puts the data in buf, and returns the length, in byte, of the
2545N/A * MAC address. Returns -1 if there is no hardware address on that interface.
2545N/A */
2545N/Astatic int getMacAddress(JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr, unsigned char *buf) {
2545N/A static struct ifreq ifr;
2545N/A int i;
0N/A
2545N/A strcpy(ifr.ifr_name, ifname);
2545N/A if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
2545N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFHWADDR failed");
2545N/A return -1;
2545N/A }
2545N/A
2545N/A memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
2545N/A
2545N/A /*
2545N/A * All bytes to 0 means no hardware address.
2545N/A */
2545N/A
2545N/A for (i = 0; i < IFHWADDRLEN; i++) {
2545N/A if (buf[i] != 0)
2545N/A return IFHWADDRLEN;
2545N/A }
2545N/A
0N/A return -1;
2545N/A}
2545N/A
2545N/Astatic int getMTU(JNIEnv *env, int sock, const char *ifname) {
2545N/A struct ifreq if2;
2545N/A
2545N/A memset((char *) &if2, 0, sizeof(if2));
2545N/A strcpy(if2.ifr_name, ifname);
2545N/A
2545N/A if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
2545N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFMTU failed");
2545N/A return -1;
2545N/A }
2545N/A
2545N/A return if2.ifr_mtu;
2545N/A}
2545N/A
5523N/Astatic int getFlags(int sock, const char *ifname, int *flags) {
2545N/A struct ifreq if2;
0N/A
0N/A memset((char *) &if2, 0, sizeof(if2));
0N/A strcpy(if2.ifr_name, ifname);
2545N/A
2545N/A if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0){
2545N/A return -1;
2545N/A }
2545N/A
5523N/A if (sizeof(if2.ifr_flags) == sizeof(short)) {
5523N/A *flags = (if2.ifr_flags & 0xffff);
5523N/A } else {
5523N/A *flags = if2.ifr_flags;
5523N/A }
5523N/A return 0;
2545N/A}
2545N/A
2545N/A#endif
2545N/A
2545N/A/** Solaris **/
2545N/A#ifdef __solaris__
2545N/A/* Open socket for further ioct calls, try v4 socket first and
2545N/A * if it falls return v6 socket
2545N/A */
2545N/A
2545N/A#ifdef AF_INET6
2545N/Astatic int openSocketWithFallback(JNIEnv *env, const char *ifname){
2545N/A int sock, alreadyV6 = 0;
2545N/A struct lifreq if2;
2545N/A
2545N/A if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
2545N/A if (errno == EPROTONOSUPPORT){
2545N/A if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
2545N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
2545N/A return -1;
2545N/A }
2545N/A
2545N/A alreadyV6=1;
2545N/A }
2545N/A else{ // errno is not NOSUPPORT
2545N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
2545N/A return -1;
2545N/A }
2545N/A }
2545N/A
2545N/A /**
2545N/A * Solaris requires that we have IPv6 socket to query an
2545N/A * interface without IPv4 address - check it here
2545N/A * POSIX 1 require the kernell to return ENOTTY if the call is
2545N/A * unappropriate for device e.g. NETMASK for device having IPv6
2545N/A * only address but not all devices follows the standart so
2545N/A * fallback on any error. It's not an ecology friendly but more
2545N/A * reliable.
2545N/A */
2545N/A
2545N/A if (! alreadyV6 ){
2545N/A memset((char *) &if2, 0, sizeof(if2));
2545N/A strcpy(if2.lifr_name, ifname);
2545N/A if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
2545N/A close(sock);
2545N/A if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
2545N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
2545N/A return -1;
2545N/A }
2545N/A }
0N/A }
2545N/A
2545N/A return sock;
2545N/A}
2545N/A
2545N/A#else
2545N/Astatic int openSocketWithFallback(JNIEnv *env, const char *ifname){
2545N/A return openSocket(env,AF_INET);
2545N/A}
2545N/A#endif
2545N/A
2545N/A/*
2545N/A * Enumerates and returns all IPv4 interfaces
2545N/A * (linux verison)
2545N/A */
2545N/A
2545N/Astatic netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
2545N/A return enumIPvXInterfaces(env,sock, ifs, AF_INET);
0N/A}
0N/A
2545N/A#ifdef AF_INET6
2545N/Astatic netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
2545N/A return enumIPvXInterfaces(env,sock, ifs, AF_INET6);
2545N/A}
2545N/A#endif
2545N/A
2545N/A/*
2545N/A Enumerates and returns all interfaces on Solaris
2545N/A use the same code for IPv4 and IPv6
2545N/A */
2545N/Astatic netif *enumIPvXInterfaces(JNIEnv *env, int sock, netif *ifs, int family) {
2545N/A struct lifconf ifc;
2545N/A struct lifreq *ifr;
2545N/A int n;
2545N/A char *buf;
2545N/A struct lifnum numifs;
2545N/A unsigned bufsize;
2545N/A
2545N/A /*
2545N/A * Get the interface count
2545N/A */
2545N/A numifs.lifn_family = family;
2545N/A numifs.lifn_flags = 0;
2545N/A if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {
2545N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGLIFNUM failed");
2545N/A return ifs;
2545N/A }
2545N/A
2545N/A /*
2545N/A * Enumerate the interface configurations
2545N/A */
2545N/A bufsize = numifs.lifn_count * sizeof (struct lifreq);
2545N/A CHECKED_MALLOC3(buf, char *, bufsize);
2545N/A
2545N/A ifc.lifc_family = family;
2545N/A ifc.lifc_flags = 0;
2545N/A ifc.lifc_len = bufsize;
2545N/A ifc.lifc_buf = buf;
2545N/A if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {
2545N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "ioctl SIOCGLIFCONF failed");
2545N/A free(buf);
2545N/A return ifs;
2545N/A }
2545N/A
2545N/A /*
2545N/A * Iterate through each interface
2545N/A */
2545N/A ifr = ifc.lifc_req;
2545N/A for (n=0; n<numifs.lifn_count; n++, ifr++) {
2545N/A int index = -1;
2545N/A struct lifreq if2;
2545N/A
2545N/A /*
2545N/A * Ignore either IPv4 or IPv6 addresses
2545N/A */
2545N/A if (ifr->lifr_addr.ss_family != family) {
2545N/A continue;
2545N/A }
2545N/A
2578N/A#ifdef AF_INET6
2578N/A if (ifr->lifr_addr.ss_family == AF_INET6) {
2578N/A struct sockaddr_in6 *s6= (struct sockaddr_in6 *)&(ifr->lifr_addr);
2578N/A s6->sin6_scope_id = getIndex(sock, ifr->lifr_name);
2578N/A }
2578N/A#endif
2578N/A
2545N/A /* add to the list */
2545N/A ifs = addif(env, sock,ifr->lifr_name, ifs, (struct sockaddr *)&(ifr->lifr_addr),family, (short) ifr->lifr_addrlen);
2545N/A
2545N/A /*
2545N/A * If an exception occurred we return immediately
2545N/A */
2545N/A if ((*env)->ExceptionOccurred(env)) {
2545N/A free(buf);
2545N/A return ifs;
2545N/A }
2545N/A
2545N/A }
2545N/A
2545N/A free(buf);
2545N/A return ifs;
2545N/A}
2545N/A
2578N/Astatic int getIndex(int sock, const char *name){
2545N/A /*
2545N/A * Try to get the interface index
2545N/A * (Not supported on Solaris 2.6 or 7)
2545N/A */
2545N/A struct lifreq if2;
2545N/A strcpy(if2.lifr_name, name);
2545N/A
2545N/A if (ioctl(sock, SIOCGLIFINDEX, (char *)&if2) < 0) {
2545N/A return -1;
2545N/A }
2545N/A
2545N/A return if2.lifr_index;
2545N/A}
2545N/A
2545N/A/**
2545N/A * Returns the IPv4 broadcast address of a named interface, if it exists.
2545N/A * Returns 0 if it doesn't have one.
2545N/A */
2545N/Astatic struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) {
2545N/A struct sockaddr *ret = NULL;
2545N/A struct lifreq if2;
2545N/A
2545N/A memset((char *) &if2, 0, sizeof(if2));
2545N/A strcpy(if2.lifr_name, ifname);
2545N/A
2545N/A /* Let's make sure the interface does have a broadcast address */
2545N/A if (ioctl(sock, SIOCGLIFFLAGS, (char *)&if2) < 0) {
2545N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFFLAGS failed");
2545N/A return ret;
2545N/A }
2545N/A
2545N/A if (if2.lifr_flags & IFF_BROADCAST) {
2545N/A /* It does, let's retrieve it*/
2545N/A if (ioctl(sock, SIOCGLIFBRDADDR, (char *)&if2) < 0) {
2545N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFBRDADDR failed");
2545N/A return ret;
2545N/A }
2545N/A
2545N/A ret = brdcast_store;
2545N/A memcpy(ret, &if2.lifr_broadaddr, sizeof(struct sockaddr));
2545N/A }
2545N/A
2545N/A return ret;
2545N/A}
2545N/A
2545N/A/**
2545N/A * Returns the IPv4 subnet prefix length (aka subnet mask) for the named
2545N/A * interface, if it has one, otherwise return -1.
2545N/A */
2545N/Astatic short getSubnet(JNIEnv *env, int sock, const char *ifname) {
2545N/A unsigned int mask;
2545N/A short ret;
2545N/A struct lifreq if2;
2545N/A
2545N/A memset((char *) &if2, 0, sizeof(if2));
2545N/A strcpy(if2.lifr_name, ifname);
2545N/A
2545N/A if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
2545N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFNETMASK failed");
2545N/A return -1;
2545N/A }
2545N/A
2545N/A mask = ntohl(((struct sockaddr_in*)&(if2.lifr_addr))->sin_addr.s_addr);
2545N/A ret = 0;
2545N/A
2545N/A while (mask) {
2545N/A mask <<= 1;
2545N/A ret++;
2545N/A }
2545N/A
2545N/A return ret;
2545N/A}
2545N/A
2545N/A
2545N/A
2545N/A#define DEV_PREFIX "/dev/"
0N/A
0N/A/**
0N/A * Solaris specific DLPI code to get hardware address from a device.
0N/A * Unfortunately, at least up to Solaris X, you have to have special
0N/A * privileges (i.e. be root).
0N/A */
0N/Astatic int getMacFromDevice(JNIEnv *env, const char* ifname, unsigned char* retbuf) {
2545N/A char style1dev[MAXPATHLEN];
2545N/A int fd;
2545N/A dl_phys_addr_req_t dlpareq;
2545N/A dl_phys_addr_ack_t *dlpaack;
2545N/A struct strbuf msg;
2545N/A char buf[128];
2545N/A int flags = 0;
2545N/A
2545N/A /**
2545N/A * Device is in /dev
2545N/A * e.g.: /dev/bge0
2545N/A */
2545N/A strcpy(style1dev, DEV_PREFIX);
2545N/A strcat(style1dev, ifname);
2545N/A if ((fd = open(style1dev, O_RDWR)) < 0) {
2545N/A /*
2545N/A * Can't open it. We probably are missing the privilege.
2545N/A * We'll have to try something else
2545N/A */
2545N/A return 0;
2545N/A }
2545N/A
2545N/A dlpareq.dl_primitive = DL_PHYS_ADDR_REQ;
2545N/A dlpareq.dl_addr_type = DL_CURR_PHYS_ADDR;
0N/A
2545N/A msg.buf = (char *)&dlpareq;
2545N/A msg.len = DL_PHYS_ADDR_REQ_SIZE;
2545N/A
2545N/A if (putmsg(fd, &msg, NULL, 0) < 0) {
2545N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "putmsg failed");
2545N/A return -1;
2545N/A }
2545N/A
2545N/A dlpaack = (dl_phys_addr_ack_t *)buf;
0N/A
2545N/A msg.buf = (char *)buf;
2545N/A msg.len = 0;
2545N/A msg.maxlen = sizeof (buf);
2545N/A if (getmsg(fd, &msg, NULL, &flags) < 0) {
2545N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "getmsg failed");
2545N/A return -1;
2545N/A }
2545N/A
2545N/A if (msg.len < DL_PHYS_ADDR_ACK_SIZE || dlpaack->dl_primitive != DL_PHYS_ADDR_ACK) {
2545N/A JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Couldn't obtain phys addr\n");
2545N/A return -1;
2545N/A }
2545N/A
2545N/A memcpy(retbuf, &buf[dlpaack->dl_addr_offset], dlpaack->dl_addr_length);
2545N/A return dlpaack->dl_addr_length;
0N/A}
0N/A
0N/A/**
0N/A * Get the Hardware address (usually MAC address) for the named interface.
0N/A * return puts the data in buf, and returns the length, in byte, of the
0N/A * MAC address. Returns -1 if there is no hardware address on that interface.
0N/A */
2545N/Astatic int getMacAddress(JNIEnv *env, int sock, const char *ifname, const struct in_addr* addr, unsigned char *buf) {
2545N/A struct arpreq arpreq;
2545N/A struct sockaddr_in* sin;
2545N/A struct sockaddr_in ipAddr;
2545N/A int len, i;
4501N/A struct lifreq lif;
4501N/A
4501N/A /* First, try the new (S11) SIOCGLIFHWADDR ioctl(). If that fails
4501N/A * try the old way.
4501N/A */
4501N/A memset(&lif, 0, sizeof(lif));
4501N/A strlcpy(lif.lifr_name, ifname, sizeof(lif.lifr_name));
4501N/A
4501N/A if (ioctl(sock, SIOCGLIFHWADDR, &lif) != -1) {
4501N/A struct sockaddr_dl *sp;
4501N/A sp = (struct sockaddr_dl *)&lif.lifr_addr;
4501N/A memcpy(buf, &sp->sdl_data[0], sp->sdl_alen);
4501N/A return sp->sdl_alen;
4501N/A }
2545N/A
2545N/A /**
2545N/A * On Solaris we have to use DLPI, but it will only work if we have
2545N/A * privileged access (i.e. root). If that fails, we try a lookup
2545N/A * in the ARP table, which requires an IPv4 address.
2545N/A */
2545N/A if ((len = getMacFromDevice(env, ifname, buf)) == 0) {
2545N/A /*DLPI failed - trying to do arp lookup*/
2545N/A
4501N/A if (addr == NULL) {
4501N/A /**
4501N/A * No IPv4 address for that interface, so can't do an ARP lookup.
4501N/A */
4501N/A return -1;
4501N/A }
0N/A
4501N/A len = 6; //???
2545N/A
4501N/A sin = (struct sockaddr_in *) &arpreq.arp_pa;
4501N/A memset((char *) &arpreq, 0, sizeof(struct arpreq));
4501N/A ipAddr.sin_port = 0;
4501N/A ipAddr.sin_family = AF_INET;
4501N/A memcpy(&ipAddr.sin_addr, addr, sizeof(struct in_addr));
4501N/A memcpy(&arpreq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
4501N/A arpreq.arp_flags= ATF_PUBL;
0N/A
4501N/A if (ioctl(sock, SIOCGARP, &arpreq) < 0) {
4501N/A return -1;
4501N/A }
2545N/A
4501N/A memcpy(buf, &arpreq.arp_ha.sa_data[0], len );
4501N/A }
0N/A
2545N/A /*
2545N/A * All bytes to 0 means no hardware address.
0N/A */
0N/A
2545N/A for (i = 0; i < len; i++) {
2545N/A if (buf[i] != 0)
2545N/A return len;
2545N/A }
0N/A
2545N/A return -1;
0N/A}
0N/A
2545N/Astatic int getMTU(JNIEnv *env, int sock, const char *ifname) {
2545N/A struct lifreq if2;
0N/A
2545N/A memset((char *) &if2, 0, sizeof(if2));
2545N/A strcpy(if2.lifr_name, ifname);
0N/A
2545N/A if (ioctl(sock, SIOCGLIFMTU, (char *)&if2) < 0) {
2545N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGLIFMTU failed");
2545N/A return -1;
2545N/A }
0N/A
2545N/A return if2.lifr_mtu;
0N/A}
0N/A
0N/A
5523N/Astatic int getFlags(int sock, const char *ifname, int *flags) {
2545N/A struct lifreq lifr;
2545N/A memset((caddr_t)&lifr, 0, sizeof(lifr));
2545N/A strcpy((caddr_t)&(lifr.lifr_name), ifname);
0N/A
2545N/A if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
2545N/A return -1;
2545N/A }
375N/A
5523N/A *flags = lifr.lifr_flags;
5523N/A return 0;
2545N/A}
2545N/A
375N/A
2112N/A#endif
2545N/A
2545N/A
4632N/A/** BSD **/
4632N/A#ifdef _ALLBSD_SOURCE
4632N/A/* Open socket for further ioct calls, try v4 socket first and
4632N/A * if it falls return v6 socket
4632N/A */
4632N/A
4632N/A#ifdef AF_INET6
4632N/Astatic int openSocketWithFallback(JNIEnv *env, const char *ifname){
4632N/A int sock;
4632N/A struct ifreq if2;
4632N/A
4632N/A if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
4632N/A if (errno == EPROTONOSUPPORT){
4632N/A if ( (sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0 ){
4632N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
4632N/A return -1;
4632N/A }
4632N/A }
4632N/A else{ // errno is not NOSUPPORT
4632N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
4632N/A return -1;
4632N/A }
4632N/A }
4632N/A
4632N/A return sock;
4632N/A}
4632N/A
4632N/A#else
4632N/Astatic int openSocketWithFallback(JNIEnv *env, const char *ifname){
4632N/A return openSocket(env,AF_INET);
4632N/A}
4632N/A#endif
4632N/A
4632N/A/*
4632N/A * Enumerates and returns all IPv4 interfaces
4632N/A */
4632N/Astatic netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
4632N/A struct ifaddrs *ifa, *origifa;
4632N/A
4632N/A if (getifaddrs(&origifa) != 0) {
4632N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException",
4632N/A "getifaddrs() function failed");
4632N/A return ifs;
4632N/A }
4632N/A
4632N/A for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
4632N/A
4632N/A /*
4632N/A * Skip non-AF_INET entries.
4632N/A */
4632N/A if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)
4632N/A continue;
4632N/A
4632N/A /*
4632N/A * Add to the list.
4632N/A */
4632N/A ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, AF_INET, 0);
4632N/A
4632N/A /*
4632N/A * If an exception occurred then free the list.
4632N/A */
4632N/A if ((*env)->ExceptionOccurred(env)) {
4632N/A freeifaddrs(origifa);
4632N/A freeif(ifs);
4632N/A return NULL;
4632N/A }
4632N/A }
4632N/A
4632N/A /*
4632N/A * Free socket and buffer
4632N/A */
4632N/A freeifaddrs(origifa);
4632N/A return ifs;
4632N/A}
4632N/A
4632N/A
4632N/A/*
4632N/A * Enumerates and returns all IPv6 interfaces on Linux
4632N/A */
4632N/A
4632N/A#ifdef AF_INET6
4632N/A/*
4632N/A * Determines the prefix on BSD for IPv6 interfaces.
4632N/A */
4632N/Astatic
4632N/Aint prefix(void *val, int size) {
4632N/A u_char *name = (u_char *)val;
4632N/A int byte, bit, plen = 0;
4632N/A
4632N/A for (byte = 0; byte < size; byte++, plen += 8)
4632N/A if (name[byte] != 0xff)
4632N/A break;
4632N/A if (byte == size)
4632N/A return (plen);
4632N/A for (bit = 7; bit != 0; bit--, plen++)
4632N/A if (!(name[byte] & (1 << bit)))
4632N/A break;
4632N/A for (; bit != 0; bit--)
4632N/A if (name[byte] & (1 << bit))
4632N/A return (0);
4632N/A byte++;
4632N/A for (; byte < size; byte++)
4632N/A if (name[byte])
4632N/A return (0);
4632N/A return (plen);
4632N/A}
4632N/A
4632N/A/*
4632N/A * Enumerates and returns all IPv6 interfaces on BSD
4632N/A */
4632N/Astatic netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
4632N/A struct ifaddrs *ifa, *origifa;
4632N/A struct sockaddr_in6 *sin6;
4632N/A struct in6_ifreq ifr6;
4632N/A
4632N/A if (getifaddrs(&origifa) != 0) {
4632N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException",
4632N/A "getifaddrs() function failed");
4632N/A return ifs;
4632N/A }
4632N/A
4632N/A for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {
4632N/A
4632N/A /*
4632N/A * Skip non-AF_INET6 entries.
4632N/A */
4632N/A if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET6)
4632N/A continue;
4632N/A
4632N/A memset(&ifr6, 0, sizeof(ifr6));
4632N/A strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
4632N/A memcpy(&ifr6.ifr_addr, ifa->ifa_addr, MIN(sizeof(ifr6.ifr_addr), ifa->ifa_addr->sa_len));
4632N/A
4632N/A if (ioctl(sock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0) {
4632N/A NET_ThrowByNameWithLastError(env , JNU_JAVANETPKG "SocketException",
4632N/A "ioctl SIOCGIFNETMASK_IN6 failed");
4632N/A freeifaddrs(origifa);
4632N/A freeif(ifs);
4632N/A return NULL;
4632N/A }
4632N/A
4632N/A /* Add to the list. */
4632N/A sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
4632N/A ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, AF_INET6,
4632N/A prefix(&sin6->sin6_addr, sizeof(struct in6_addr)));
4632N/A
4632N/A /* If an exception occurred then free the list. */
4632N/A if ((*env)->ExceptionOccurred(env)) {
4632N/A freeifaddrs(origifa);
4632N/A freeif(ifs);
4632N/A return NULL;
4632N/A }
4632N/A }
4632N/A
4632N/A /*
4632N/A * Free socket and ifaddrs buffer
4632N/A */
4632N/A freeifaddrs(origifa);
4632N/A return ifs;
4632N/A}
4632N/A#endif
4632N/A
4632N/Astatic int getIndex(int sock, const char *name){
4632N/A#ifdef __FreeBSD__
4632N/A /*
4632N/A * Try to get the interface index
4632N/A * (Not supported on Solaris 2.6 or 7)
4632N/A */
4632N/A struct ifreq if2;
4632N/A strcpy(if2.ifr_name, name);
4632N/A
4632N/A if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {
4632N/A return -1;
4632N/A }
4632N/A
4632N/A return if2.ifr_index;
4632N/A#else
4632N/A /*
4632N/A * Try to get the interface index using BSD specific if_nametoindex
4632N/A */
4632N/A int index = if_nametoindex(name);
4632N/A return (index == 0) ? -1 : index;
4632N/A#endif
4632N/A}
4632N/A
4632N/A/**
4632N/A * Returns the IPv4 broadcast address of a named interface, if it exists.
4632N/A * Returns 0 if it doesn't have one.
4632N/A */
4632N/Astatic struct sockaddr *getBroadcast(JNIEnv *env, int sock, const char *ifname, struct sockaddr *brdcast_store) {
4632N/A struct sockaddr *ret = NULL;
4632N/A struct ifreq if2;
4632N/A
4632N/A memset((char *) &if2, 0, sizeof(if2));
4632N/A strcpy(if2.ifr_name, ifname);
4632N/A
4632N/A /* Let's make sure the interface does have a broadcast address */
4632N/A if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {
4632N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFFLAGS failed");
4632N/A return ret;
4632N/A }
4632N/A
4632N/A if (if2.ifr_flags & IFF_BROADCAST) {
4632N/A /* It does, let's retrieve it*/
4632N/A if (ioctl(sock, SIOCGIFBRDADDR, (char *)&if2) < 0) {
4632N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFBRDADDR failed");
4632N/A return ret;
4632N/A }
4632N/A
4632N/A ret = brdcast_store;
4632N/A memcpy(ret, &if2.ifr_broadaddr, sizeof(struct sockaddr));
4632N/A }
4632N/A
4632N/A return ret;
4632N/A}
4632N/A
4632N/A/**
4632N/A * Returns the IPv4 subnet prefix length (aka subnet mask) for the named
4632N/A * interface, if it has one, otherwise return -1.
4632N/A */
4632N/Astatic short getSubnet(JNIEnv *env, int sock, const char *ifname) {
4632N/A unsigned int mask;
4632N/A short ret;
4632N/A struct ifreq if2;
4632N/A
4632N/A memset((char *) &if2, 0, sizeof(if2));
4632N/A strcpy(if2.ifr_name, ifname);
4632N/A
4632N/A if (ioctl(sock, SIOCGIFNETMASK, (char *)&if2) < 0) {
4632N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFNETMASK failed");
4632N/A return -1;
4632N/A }
4632N/A
4632N/A mask = ntohl(((struct sockaddr_in*)&(if2.ifr_addr))->sin_addr.s_addr);
4632N/A ret = 0;
4632N/A while (mask) {
4632N/A mask <<= 1;
4632N/A ret++;
4632N/A }
4632N/A
4632N/A return ret;
4632N/A}
4632N/A
4632N/A/**
4632N/A * Get the Hardware address (usually MAC address) for the named interface.
4632N/A * return puts the data in buf, and returns the length, in byte, of the
4632N/A * MAC address. Returns -1 if there is no hardware address on that interface.
4632N/A */
4632N/Astatic int getMacAddress(JNIEnv *env, int sock, const char* ifname, const struct in_addr* addr, unsigned char *buf) {
4632N/A struct ifaddrs *ifa0, *ifa;
4632N/A struct sockaddr *saddr;
4632N/A int i;
4632N/A
4632N/A /* Grab the interface list */
4632N/A if (!getifaddrs(&ifa0)) {
4632N/A /* Cycle through the interfaces */
4632N/A for (i = 0, ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next, i++) {
4632N/A saddr = ifa->ifa_addr;
4632N/A /* Link layer contains the MAC address */
4632N/A if (saddr->sa_family == AF_LINK && !strcmp(ifname, ifa->ifa_name)) {
4632N/A struct sockaddr_dl *sadl = (struct sockaddr_dl *) saddr;
4632N/A /* Check the address is the correct length */
4632N/A if (sadl->sdl_alen == ETHER_ADDR_LEN) {
4632N/A memcpy(buf, (sadl->sdl_data + sadl->sdl_nlen), ETHER_ADDR_LEN);
4632N/A freeifaddrs(ifa0);
4632N/A return ETHER_ADDR_LEN;
4632N/A }
4632N/A }
4632N/A }
4632N/A freeifaddrs(ifa0);
4632N/A }
4632N/A
4632N/A return -1;
4632N/A}
4632N/A
4632N/Astatic int getMTU(JNIEnv *env, int sock, const char *ifname) {
4632N/A struct ifreq if2;
4632N/A
4632N/A memset((char *) &if2, 0, sizeof(if2));
4632N/A strcpy(if2.ifr_name, ifname);
4632N/A
4632N/A if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {
4632N/A NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "IOCTL SIOCGIFMTU failed");
4632N/A return -1;
4632N/A }
4632N/A
4632N/A return if2.ifr_mtu;
4632N/A}
4632N/A
5523N/Astatic int getFlags(int sock, const char *ifname, int *flags) {
4632N/A struct ifreq if2;
4632N/A int ret = -1;
4632N/A
4632N/A memset((char *) &if2, 0, sizeof(if2));
4632N/A strcpy(if2.ifr_name, ifname);
4632N/A
4632N/A if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0){
4632N/A return -1;
4632N/A }
4632N/A
5523N/A if (sizeof(if2.ifr_flags) == sizeof(short)) {
5523N/A *flags = (if2.ifr_flags & 0xffff);
5523N/A } else {
5523N/A *flags = if2.ifr_flags;
5523N/A }
5523N/A return 0;
4632N/A}
4632N/A
4632N/A#endif