Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/java/net/NetworkInterface.c
32287 views
/*1* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <errno.h>26#include <strings.h>27#include <netinet/in.h>28#include <stdlib.h>29#include <string.h>30#include <sys/types.h>31#include <sys/socket.h>32#include <arpa/inet.h>33#include <net/if.h>34#include <net/if_arp.h>3536#if defined(__solaris__)37#include <sys/dlpi.h>38#include <fcntl.h>39#include <stropts.h>40#include <sys/sockio.h>41#endif4243#if defined(__linux__)44#include <sys/ioctl.h>45#include <sys/utsname.h>46#include <stdio.h>47#endif4849#if defined(_AIX)50#include <sys/ioctl.h>51#include <netinet/in6_var.h>52#include <sys/ndd_var.h>53#include <sys/kinfo.h>54#endif5556#if defined(_ALLBSD_SOURCE)57#include <sys/param.h>58#include <sys/ioctl.h>59#include <sys/sockio.h>60#if defined(__APPLE__)61#include <net/ethernet.h>62#include <net/if_var.h>63#include <net/if_dl.h>64#include <netinet/in_var.h>65#include <ifaddrs.h>66#endif67#endif6869#include "jvm.h"70#include "jni_util.h"71#include "net_util.h"7273#if defined(__linux__)74#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"75#elif defined(__solaris__)76#ifndef SIOCGLIFHWADDR77#define SIOCGLIFHWADDR _IOWR('i', 192, struct lifreq)78#endif79#define DEV_PREFIX "/dev/"80#endif8182#ifdef LIFNAMSIZ83#define IFNAMESIZE LIFNAMSIZ84#else85#define IFNAMESIZE IFNAMSIZ86#endif8788#define CHECKED_MALLOC3(_pointer, _type, _size) \89do { \90_pointer = (_type)malloc(_size); \91if (_pointer == NULL) { \92JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed"); \93return ifs; /* return untouched list */ \94} \95} while(0)9697typedef struct _netaddr {98struct sockaddr *addr;99struct sockaddr *brdcast;100short mask;101int family; /* to make searches simple */102struct _netaddr *next;103} netaddr;104105typedef struct _netif {106char *name;107int index;108char virtual;109netaddr *addr;110struct _netif *childs;111struct _netif *next;112} netif;113114/************************************************************************115* NetworkInterface116*/117118#include "java_net_NetworkInterface.h"119120/************************************************************************121* NetworkInterface122*/123jclass ni_class;124jfieldID ni_nameID;125jfieldID ni_indexID;126jfieldID ni_descID;127jfieldID ni_addrsID;128jfieldID ni_bindsID;129jfieldID ni_virutalID;130jfieldID ni_childsID;131jfieldID ni_parentID;132jfieldID ni_defaultIndexID;133jmethodID ni_ctrID;134135static jclass ni_ibcls;136static jmethodID ni_ibctrID;137static jfieldID ni_ibaddressID;138static jfieldID ni_ib4broadcastID;139static jfieldID ni_ib4maskID;140141/** Private methods declarations **/142static jobject createNetworkInterface(JNIEnv *env, netif *ifs);143static int getFlags0(JNIEnv *env, jstring ifname);144145static netif *enumInterfaces(JNIEnv *env);146static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs);147148#if defined(AF_INET6)149static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs);150#endif151152static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,153struct sockaddr *ifr_addrP,154struct sockaddr *ifr_broadaddrP,155int family, short prefix);156static void freeif(netif *ifs);157158static int openSocket(JNIEnv *env, int proto);159static int openSocketWithFallback(JNIEnv *env, const char *ifname);160161static short translateIPv4AddressToPrefix(struct sockaddr_in *addr);162static short translateIPv6AddressToPrefix(struct sockaddr_in6 *addr);163164static int getIndex(int sock, const char *ifname);165static int getFlags(int sock, const char *ifname, int *flags);166static int getMacAddress(JNIEnv *env, const char *ifname,167const struct in_addr *addr, unsigned char *buf);168static int getMTU(JNIEnv *env, int sock, const char *ifname);169170#if defined(__solaris__)171static int getMacFromDevice(JNIEnv *env, const char *ifname,172unsigned char *retbuf);173#endif174175/******************* Java entry points *****************************/176177/*178* Class: java_net_NetworkInterface179* Method: init180* Signature: ()V181*/182JNIEXPORT void JNICALL Java_java_net_NetworkInterface_init183(JNIEnv *env, jclass cls)184{185ni_class = (*env)->FindClass(env, "java/net/NetworkInterface");186CHECK_NULL(ni_class);187ni_class = (*env)->NewGlobalRef(env, ni_class);188CHECK_NULL(ni_class);189ni_nameID = (*env)->GetFieldID(env, ni_class, "name", "Ljava/lang/String;");190CHECK_NULL(ni_nameID);191ni_indexID = (*env)->GetFieldID(env, ni_class, "index", "I");192CHECK_NULL(ni_indexID);193ni_addrsID = (*env)->GetFieldID(env, ni_class, "addrs",194"[Ljava/net/InetAddress;");195CHECK_NULL(ni_addrsID);196ni_bindsID = (*env)->GetFieldID(env, ni_class, "bindings",197"[Ljava/net/InterfaceAddress;");198CHECK_NULL(ni_bindsID);199ni_descID = (*env)->GetFieldID(env, ni_class, "displayName",200"Ljava/lang/String;");201CHECK_NULL(ni_descID);202ni_virutalID = (*env)->GetFieldID(env, ni_class, "virtual", "Z");203CHECK_NULL(ni_virutalID);204ni_childsID = (*env)->GetFieldID(env, ni_class, "childs",205"[Ljava/net/NetworkInterface;");206CHECK_NULL(ni_childsID);207ni_parentID = (*env)->GetFieldID(env, ni_class, "parent",208"Ljava/net/NetworkInterface;");209CHECK_NULL(ni_parentID);210ni_ctrID = (*env)->GetMethodID(env, ni_class, "<init>", "()V");211CHECK_NULL(ni_ctrID);212ni_ibcls = (*env)->FindClass(env, "java/net/InterfaceAddress");213CHECK_NULL(ni_ibcls);214ni_ibcls = (*env)->NewGlobalRef(env, ni_ibcls);215CHECK_NULL(ni_ibcls);216ni_ibctrID = (*env)->GetMethodID(env, ni_ibcls, "<init>", "()V");217CHECK_NULL(ni_ibctrID);218ni_ibaddressID = (*env)->GetFieldID(env, ni_ibcls, "address",219"Ljava/net/InetAddress;");220CHECK_NULL(ni_ibaddressID);221ni_ib4broadcastID = (*env)->GetFieldID(env, ni_ibcls, "broadcast",222"Ljava/net/Inet4Address;");223CHECK_NULL(ni_ib4broadcastID);224ni_ib4maskID = (*env)->GetFieldID(env, ni_ibcls, "maskLength", "S");225CHECK_NULL(ni_ib4maskID);226ni_defaultIndexID = (*env)->GetStaticFieldID(env, ni_class, "defaultIndex",227"I");228CHECK_NULL(ni_defaultIndexID);229230initInetAddressIDs(env);231}232233/*234* Class: java_net_NetworkInterface235* Method: getByName0236* Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;237*/238JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0239(JNIEnv *env, jclass cls, jstring name)240{241netif *ifs, *curr;242jboolean isCopy;243const char* name_utf;244jobject obj = NULL;245246if (name != NULL) {247name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);248} else {249JNU_ThrowNullPointerException(env, "network interface name is NULL");250return NULL;251}252253if (name_utf == NULL) {254if (!(*env)->ExceptionCheck(env))255JNU_ThrowOutOfMemoryError(env, NULL);256return NULL;257}258259ifs = enumInterfaces(env);260if (ifs == NULL) {261(*env)->ReleaseStringUTFChars(env, name, name_utf);262return NULL;263}264265// search the list of interfaces based on name266curr = ifs;267while (curr != NULL) {268if (strcmp(name_utf, curr->name) == 0) {269break;270}271curr = curr->next;272}273274// if found create a NetworkInterface275if (curr != NULL) {276obj = createNetworkInterface(env, curr);277}278279// release the UTF string and interface list280(*env)->ReleaseStringUTFChars(env, name, name_utf);281freeif(ifs);282283return obj;284}285286/*287* Class: java_net_NetworkInterface288* Method: getByIndex0289* Signature: (Ljava/lang/String;)Ljava/net/NetworkInterface;290*/291JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0292(JNIEnv *env, jclass cls, jint index)293{294netif *ifs, *curr;295jobject obj = NULL;296297if (index <= 0) {298return NULL;299}300301ifs = enumInterfaces(env);302if (ifs == NULL) {303return NULL;304}305306// search the list of interfaces based on index307curr = ifs;308while (curr != NULL) {309if (index == curr->index) {310break;311}312curr = curr->next;313}314315// if found create a NetworkInterface316if (curr != NULL) {317obj = createNetworkInterface(env, curr);318}319320// release the interface list321freeif(ifs);322323return obj;324}325326/*327* Class: java_net_NetworkInterface328* Method: getByInetAddress0329* Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;330*/331JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0332(JNIEnv *env, jclass cls, jobject iaObj)333{334netif *ifs, *curr;335jobject obj = NULL;336jboolean match = JNI_FALSE;337#if defined(AF_INET6)338int family = getInetAddress_family(env, iaObj);339JNU_CHECK_EXCEPTION_RETURN(env, NULL);340341if (family == IPv4) {342family = AF_INET;343} else if (family == IPv6) {344family = AF_INET6;345} else {346return NULL; // Invalid family347}348#else349int family = AF_INET;350#endif351ifs = enumInterfaces(env);352if (ifs == NULL) {353return NULL;354}355356curr = ifs;357while (curr != NULL) {358netaddr *addrP = curr->addr;359360// iterate through each address on the interface361while (addrP != NULL) {362363if (family == addrP->family) {364if (family == AF_INET) {365int address1 = htonl(366((struct sockaddr_in *)addrP->addr)->sin_addr.s_addr);367int address2 = getInetAddress_addr(env, iaObj);368if ((*env)->ExceptionCheck(env)) {369goto cleanup;370}371if (address1 == address2) {372match = JNI_TRUE;373break;374}375}376#if defined(AF_INET6)377if (family == AF_INET6) {378jbyte *bytes = (jbyte *)&(379((struct sockaddr_in6*)addrP->addr)->sin6_addr);380jbyte caddr[16];381int i;382getInet6Address_ipaddress(env, iaObj, (char *)caddr);383i = 0;384while (i < 16) {385if (caddr[i] != bytes[i]) {386break;387}388i++;389}390if (i >= 16) {391match = JNI_TRUE;392break;393}394}395#endif396}397398if (match) {399break;400}401addrP = addrP->next;402}403404if (match) {405break;406}407curr = curr->next;408}409410// if found create a NetworkInterface411if (match) {412obj = createNetworkInterface(env, curr);413}414415cleanup:416// release the interface list417freeif(ifs);418419return obj;420}421422/*423* Class: java_net_NetworkInterface424* Method: getAll425* Signature: ()[Ljava/net/NetworkInterface;426*/427JNIEXPORT jobjectArray JNICALL Java_java_net_NetworkInterface_getAll428(JNIEnv *env, jclass cls)429{430netif *ifs, *curr;431jobjectArray netIFArr;432jint arr_index, ifCount;433434ifs = enumInterfaces(env);435if (ifs == NULL) {436return NULL;437}438439// count the interfaces440ifCount = 0;441curr = ifs;442while (curr != NULL) {443ifCount++;444curr = curr->next;445}446447// allocate a NetworkInterface array448netIFArr = (*env)->NewObjectArray(env, ifCount, cls, NULL);449if (netIFArr == NULL) {450freeif(ifs);451return NULL;452}453454// iterate through the interfaces, create a NetworkInterface instance455// for each array element and populate the object456curr = ifs;457arr_index = 0;458while (curr != NULL) {459jobject netifObj;460461netifObj = createNetworkInterface(env, curr);462if (netifObj == NULL) {463freeif(ifs);464return NULL;465}466467// put the NetworkInterface into the array468(*env)->SetObjectArrayElement(env, netIFArr, arr_index++, netifObj);469470curr = curr->next;471}472473// release the interface list474freeif(ifs);475476return netIFArr;477}478479/*480* Class: java_net_NetworkInterface481* Method: isUp0482* Signature: (Ljava/lang/String;I)Z483*/484JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isUp0485(JNIEnv *env, jclass cls, jstring name, jint index)486{487int ret = getFlags0(env, name);488return ((ret & IFF_UP) && (ret & IFF_RUNNING)) ? JNI_TRUE : JNI_FALSE;489}490491/*492* Class: java_net_NetworkInterface493* Method: isP2P0494* Signature: (Ljava/lang/String;I)Z495*/496JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isP2P0497(JNIEnv *env, jclass cls, jstring name, jint index)498{499int ret = getFlags0(env, name);500return (ret & IFF_POINTOPOINT) ? JNI_TRUE : JNI_FALSE;501}502503/*504* Class: java_net_NetworkInterface505* Method: isLoopback0506* Signature: (Ljava/lang/String;I)Z507*/508JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0509(JNIEnv *env, jclass cls, jstring name, jint index)510{511int ret = getFlags0(env, name);512return (ret & IFF_LOOPBACK) ? JNI_TRUE : JNI_FALSE;513}514515/*516* Class: java_net_NetworkInterface517* Method: supportsMulticast0518* Signature: (Ljava/lang/String;I)Z519*/520JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_supportsMulticast0521(JNIEnv *env, jclass cls, jstring name, jint index)522{523int ret = getFlags0(env, name);524return (ret & IFF_MULTICAST) ? JNI_TRUE : JNI_FALSE;525}526527/*528* Class: java_net_NetworkInterface529* Method: getMacAddr0530* Signature: ([bLjava/lang/String;I)[b531*/532JNIEXPORT jbyteArray JNICALL Java_java_net_NetworkInterface_getMacAddr0533(JNIEnv *env, jclass cls, jbyteArray addrArray, jstring name, jint index)534{535jint addr;536jbyte caddr[4];537struct in_addr iaddr;538jbyteArray ret = NULL;539unsigned char mac[16];540int len;541jboolean isCopy;542const char *name_utf;543544if (name != NULL) {545name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);546} else {547JNU_ThrowNullPointerException(env, "network interface name is NULL");548return NULL;549}550551if (name_utf == NULL) {552if (!(*env)->ExceptionCheck(env))553JNU_ThrowOutOfMemoryError(env, NULL);554return NULL;555}556557if (!IS_NULL(addrArray)) {558(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);559addr = ((caddr[0]<<24) & 0xff000000);560addr |= ((caddr[1] <<16) & 0xff0000);561addr |= ((caddr[2] <<8) & 0xff00);562addr |= (caddr[3] & 0xff);563iaddr.s_addr = htonl(addr);564len = getMacAddress(env, name_utf, &iaddr, mac);565} else {566len = getMacAddress(env, name_utf, NULL, mac);567}568569if (len > 0) {570ret = (*env)->NewByteArray(env, len);571if (!IS_NULL(ret)) {572(*env)->SetByteArrayRegion(env, ret, 0, len, (jbyte *)(mac));573}574}575576// release the UTF string and interface list577(*env)->ReleaseStringUTFChars(env, name, name_utf);578579return ret;580}581582/*583* Class: java_net_NetworkInterface584* Method: getMTU0585* Signature: ([bLjava/lang/String;I)I586*/587JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0588(JNIEnv *env, jclass cls, jstring name, jint index)589{590jboolean isCopy;591int sock, ret = -1;592const char* name_utf = NULL;593594if (name != NULL) {595name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);596} else {597JNU_ThrowNullPointerException(env, "network interface name is NULL");598return ret;599}600601if (name_utf == NULL) {602if (!(*env)->ExceptionCheck(env))603JNU_ThrowOutOfMemoryError(env, NULL);604return ret;605}606607if ((sock = openSocketWithFallback(env, name_utf)) < 0) {608(*env)->ReleaseStringUTFChars(env, name, name_utf);609return JNI_FALSE;610}611612ret = getMTU(env, sock, name_utf);613614(*env)->ReleaseStringUTFChars(env, name, name_utf);615616close(sock);617return ret;618}619620/*** Private methods definitions ****/621622static int getFlags0(JNIEnv *env, jstring name) {623jboolean isCopy;624int ret, sock, flags = 0;625const char *name_utf;626627if (name != NULL) {628name_utf = (*env)->GetStringUTFChars(env, name, &isCopy);629} else {630JNU_ThrowNullPointerException(env, "network interface name is NULL");631return -1;632}633634if (name_utf == NULL) {635if (!(*env)->ExceptionCheck(env))636JNU_ThrowOutOfMemoryError(env, NULL);637return -1;638}639if ((sock = openSocketWithFallback(env, name_utf)) < 0) {640(*env)->ReleaseStringUTFChars(env, name, name_utf);641return -1;642}643644ret = getFlags(sock, name_utf, &flags);645646close(sock);647(*env)->ReleaseStringUTFChars(env, name, name_utf);648649if (ret < 0) {650NET_ThrowByNameWithLastError651(env, JNU_JAVANETPKG "SocketException", "getFlags() failed");652return -1;653}654655return flags;656}657658/*659* Creates a NetworkInterface object, populates the name, the index, and660* populates the InetAddress array based on the IP addresses for this661* interface.662*/663static jobject createNetworkInterface(JNIEnv *env, netif *ifs) {664jobject netifObj;665jobject name;666jobjectArray addrArr;667jobjectArray bindArr;668jobjectArray childArr;669netaddr *addrs;670jint addr_index, addr_count, bind_index;671jint child_count, child_index;672netaddr *addrP;673netif *childP;674jobject tmp;675676// create a NetworkInterface object and populate it677netifObj = (*env)->NewObject(env, ni_class, ni_ctrID);678CHECK_NULL_RETURN(netifObj, NULL);679name = (*env)->NewStringUTF(env, ifs->name);680CHECK_NULL_RETURN(name, NULL);681(*env)->SetObjectField(env, netifObj, ni_nameID, name);682(*env)->SetObjectField(env, netifObj, ni_descID, name);683(*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);684(*env)->SetBooleanField(env, netifObj, ni_virutalID,685ifs->virtual ? JNI_TRUE : JNI_FALSE);686687// count the number of addresses on this interface688addr_count = 0;689addrP = ifs->addr;690while (addrP != NULL) {691addr_count++;692addrP = addrP->next;693}694695// create the array of InetAddresses696addrArr = (*env)->NewObjectArray(env, addr_count, ia_class, NULL);697if (addrArr == NULL) {698return NULL;699}700701bindArr = (*env)->NewObjectArray(env, addr_count, ni_ibcls, NULL);702if (bindArr == NULL) {703return NULL;704}705addrP = ifs->addr;706addr_index = 0;707bind_index = 0;708while (addrP != NULL) {709jobject iaObj = NULL;710jobject ibObj = NULL;711712if (addrP->family == AF_INET) {713iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);714if (iaObj) {715setInetAddress_addr(env, iaObj, htonl(716((struct sockaddr_in*)addrP->addr)->sin_addr.s_addr));717JNU_CHECK_EXCEPTION_RETURN(env, NULL);718} else {719return NULL;720}721ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);722if (ibObj) {723(*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);724if (addrP->brdcast) {725jobject ia2Obj = NULL;726ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID);727if (ia2Obj) {728setInetAddress_addr(env, ia2Obj, htonl(729((struct sockaddr_in*)addrP->brdcast)->sin_addr.s_addr));730JNU_CHECK_EXCEPTION_RETURN(env, NULL);731(*env)->SetObjectField(env, ibObj, ni_ib4broadcastID, ia2Obj);732} else {733return NULL;734}735}736(*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);737(*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);738} else {739return NULL;740}741}742#if defined(AF_INET6)743if (addrP->family == AF_INET6) {744int scope=0;745iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);746if (iaObj) {747jboolean ret = setInet6Address_ipaddress(env, iaObj,748(char *)&(((struct sockaddr_in6*)addrP->addr)->sin6_addr));749if (ret == JNI_FALSE) {750return NULL;751}752753scope = ((struct sockaddr_in6*)addrP->addr)->sin6_scope_id;754755if (scope != 0) { /* zero is default value, no need to set */756setInet6Address_scopeid(env, iaObj, scope);757setInet6Address_scopeifname(env, iaObj, netifObj);758}759} else {760return NULL;761}762ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);763if (ibObj) {764(*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);765(*env)->SetShortField(env, ibObj, ni_ib4maskID, addrP->mask);766(*env)->SetObjectArrayElement(env, bindArr, bind_index++, ibObj);767} else {768return NULL;769}770}771#endif772773(*env)->SetObjectArrayElement(env, addrArr, addr_index++, iaObj);774addrP = addrP->next;775}776777// see if there is any virtual interface attached to this one.778child_count = 0;779childP = ifs->childs;780while (childP) {781child_count++;782childP = childP->next;783}784785childArr = (*env)->NewObjectArray(env, child_count, ni_class, NULL);786if (childArr == NULL) {787return NULL;788}789790// create the NetworkInterface instances for the sub-interfaces as well791child_index = 0;792childP = ifs->childs;793while(childP) {794tmp = createNetworkInterface(env, childP);795if (tmp == NULL) {796return NULL;797}798(*env)->SetObjectField(env, tmp, ni_parentID, netifObj);799(*env)->SetObjectArrayElement(env, childArr, child_index++, tmp);800childP = childP->next;801}802(*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);803(*env)->SetObjectField(env, netifObj, ni_bindsID, bindArr);804(*env)->SetObjectField(env, netifObj, ni_childsID, childArr);805806// return the NetworkInterface807return netifObj;808}809810/*811* Enumerates all interfaces812*/813static netif *enumInterfaces(JNIEnv *env) {814netif *ifs = NULL;815int sock;816817sock = openSocket(env, AF_INET);818if (sock < 0 && (*env)->ExceptionOccurred(env)) {819return NULL;820}821822// enumerate IPv4 addresses823ifs = enumIPv4Interfaces(env, sock, NULL);824close(sock);825826// return partial list if an exception occurs in the middle of process ???827if (ifs == NULL && (*env)->ExceptionOccurred(env)) {828return NULL;829}830831// If IPv6 is available then enumerate IPv6 addresses.832#if defined(AF_INET6)833// User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,834// so we have to call ipv6_available()835if (ipv6_available()) {836sock = openSocket(env, AF_INET6);837if (sock < 0 && (*env)->ExceptionOccurred(env)) {838freeif(ifs);839return NULL;840}841842ifs = enumIPv6Interfaces(env, sock, ifs);843close(sock);844845if ((*env)->ExceptionOccurred(env)) {846freeif(ifs);847return NULL;848}849}850#endif851852return ifs;853}854855/*856* Frees an interface list (including any attached addresses).857*/858static void freeif(netif *ifs) {859netif *currif = ifs;860netif *child = NULL;861862while (currif != NULL) {863netaddr *addrP = currif->addr;864while (addrP != NULL) {865netaddr *next = addrP->next;866free(addrP);867addrP = next;868}869870// don't forget to free the sub-interfaces871if (currif->childs != NULL) {872freeif(currif->childs);873}874875ifs = currif->next;876free(currif);877currif = ifs;878}879}880881static netif *addif(JNIEnv *env, int sock, const char *if_name, netif *ifs,882struct sockaddr *ifr_addrP,883struct sockaddr *ifr_broadaddrP,884int family, short prefix)885{886netif *currif = ifs, *parent;887netaddr *addrP;888char name[IFNAMESIZE], vname[IFNAMESIZE];889char *name_colonP;890int isVirtual = 0;891int addr_size;892893// If the interface name is a logical interface then we remove the unit894// number so that we have the physical interface (eg: hme0:1 -> hme0).895// NetworkInterface currently doesn't have any concept of physical vs.896// logical interfaces.897strncpy(name, if_name, IFNAMESIZE);898name[IFNAMESIZE - 1] = '\0';899*vname = 0;900901// Create and populate the netaddr node. If allocation fails902// return an un-updated list.903904// Allocate for addr and brdcast at once905906#if defined(AF_INET6)907addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in)908: sizeof(struct sockaddr_in6);909#else910addr_size = sizeof(struct sockaddr_in);911#endif912913CHECKED_MALLOC3(addrP, netaddr *, sizeof(netaddr) + 2 * addr_size);914addrP->addr = (struct sockaddr *)((char *)addrP + sizeof(netaddr));915memcpy(addrP->addr, ifr_addrP, addr_size);916917addrP->family = family;918addrP->mask = prefix;919addrP->next = 0;920921// for IPv4 add broadcast address922if (family == AF_INET && ifr_broadaddrP != NULL) {923addrP->brdcast = (struct sockaddr *)924((char *)addrP + sizeof(netaddr) + addr_size);925memcpy(addrP->brdcast, ifr_broadaddrP, addr_size);926} else {927addrP->brdcast = NULL;928}929930// Deal with virtual interface with colon notation e.g. eth0:1931name_colonP = strchr(name, ':');932if (name_colonP != NULL) {933int flags = 0;934// This is a virtual interface. If we are able to access the parent935// we need to create a new entry if it doesn't exist yet *and* update936// the 'parent' interface with the new records.937*name_colonP = 0;938if (getFlags(sock, name, &flags) < 0 || flags < 0) {939// failed to access parent interface do not create parent.940// We are a virtual interface with no parent.941isVirtual = 1;942*name_colonP = ':';943} else {944// Got access to parent, so create it if necessary.945// Save original name to vname and truncate name by ':'946memcpy(vname, name, sizeof(vname));947vname[name_colonP - name] = ':';948}949}950951// Check if this is a "new" interface. Use the interface name for952// matching because index isn't supported on Solaris 2.6 & 7.953while (currif != NULL) {954if (strcmp(name, currif->name) == 0) {955break;956}957currif = currif->next;958}959960// If "new" then create a netif structure and insert it into the list.961if (currif == NULL) {962CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE);963currif->name = (char *)currif + sizeof(netif);964strncpy(currif->name, name, IFNAMESIZE);965currif->name[IFNAMESIZE - 1] = '\0';966currif->index = getIndex(sock, name);967currif->addr = NULL;968currif->childs = NULL;969currif->virtual = isVirtual;970currif->next = ifs;971ifs = currif;972}973974// Finally insert the address on the interface975addrP->next = currif->addr;976currif->addr = addrP;977978parent = currif;979980// Deal with the virtual interface now.981if (vname[0]) {982netaddr *tmpaddr;983984currif = parent->childs;985986while (currif != NULL) {987if (strcmp(vname, currif->name) == 0) {988break;989}990currif = currif->next;991}992993if (currif == NULL) {994CHECKED_MALLOC3(currif, netif *, sizeof(netif) + IFNAMESIZE);995currif->name = (char *)currif + sizeof(netif);996strncpy(currif->name, vname, IFNAMESIZE);997currif->name[IFNAMESIZE - 1] = '\0';998currif->index = getIndex(sock, vname);999currif->addr = NULL; // Need to duplicate the addr entry?1000currif->virtual = 1;1001currif->childs = NULL;1002currif->next = parent->childs;1003parent->childs = currif;1004}10051006CHECKED_MALLOC3(tmpaddr, netaddr *, sizeof(netaddr) + 2 * addr_size);1007memcpy(tmpaddr, addrP, sizeof(netaddr));1008if (addrP->addr != NULL) {1009tmpaddr->addr = (struct sockaddr *)1010((char*)tmpaddr + sizeof(netaddr));1011memcpy(tmpaddr->addr, addrP->addr, addr_size);1012}10131014if (addrP->brdcast != NULL) {1015tmpaddr->brdcast = (struct sockaddr *)1016((char *)tmpaddr + sizeof(netaddr) + addr_size);1017memcpy(tmpaddr->brdcast, addrP->brdcast, addr_size);1018}10191020tmpaddr->next = currif->addr;1021currif->addr = tmpaddr;1022}10231024return ifs;1025}10261027/*1028* Determines the prefix value for an AF_INET subnet address.1029*/1030static short translateIPv4AddressToPrefix(struct sockaddr_in *addr) {1031short prefix = 0;1032unsigned int mask = ntohl(addr->sin_addr.s_addr);1033while (mask) {1034mask <<= 1;1035prefix++;1036}1037return prefix;1038}10391040/*1041* Determines the prefix value for an AF_INET6 subnet address.1042*/1043static short translateIPv6AddressToPrefix(struct sockaddr_in6 *addr) {1044short prefix = 0;1045u_char *addrBytes = (u_char *)&(addr->sin6_addr);1046unsigned int byte, bit;10471048for (byte = 0; byte < sizeof(struct in6_addr); byte++, prefix += 8) {1049if (addrBytes[byte] != 0xff) {1050break;1051}1052}1053if (byte != sizeof(struct in6_addr)) {1054for (bit = 7; bit != 0; bit--, prefix++) {1055if (!(addrBytes[byte] & (1 << bit))) {1056break;1057}1058}1059for (; bit != 0; bit--) {1060if (addrBytes[byte] & (1 << bit)) {1061prefix = 0;1062break;1063}1064}1065if (prefix > 0) {1066byte++;1067for (; byte < sizeof(struct in6_addr); byte++) {1068if (addrBytes[byte]) {1069prefix = 0;1070}1071}1072}1073}10741075return prefix;1076}10771078/*1079* Opens a socket for further ioct calls. proto is one of AF_INET or AF_INET6.1080*/1081static int openSocket(JNIEnv *env, int proto) {1082int sock;10831084if ((sock = JVM_Socket(proto, SOCK_DGRAM, 0)) < 0) {1085// If EPROTONOSUPPORT is returned it means we don't have1086// support for this proto so don't throw an exception.1087if (errno != EPROTONOSUPPORT) {1088NET_ThrowByNameWithLastError1089(env, JNU_JAVANETPKG "SocketException", "Socket creation failed");1090}1091return -1;1092}10931094return sock;1095}10961097/** Linux **/1098#if defined(__linux__)10991100#if defined(AF_INET6)1101/*1102* Opens a socket for further ioctl calls. Tries AF_INET socket first and1103* if it fails return AF_INET6 socket.1104*/1105static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1106int sock;11071108if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {1109if (errno == EPROTONOSUPPORT) {1110if ((sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {1111NET_ThrowByNameWithLastError1112(env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");1113return -1;1114}1115} else { // errno is not NOSUPPORT1116NET_ThrowByNameWithLastError1117(env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");1118return -1;1119}1120}11211122// Linux starting from 2.6.? kernel allows ioctl call with either IPv4 or1123// IPv6 socket regardless of type of address of an interface.1124return sock;1125}1126#else1127static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1128return openSocket(env, AF_INET);1129}1130#endif11311132/*1133* Enumerates and returns all IPv4 interfaces on Linux.1134*/1135static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {1136struct ifconf ifc;1137struct ifreq *ifreqP;1138char *buf = NULL;1139unsigned i;11401141// do a dummy SIOCGIFCONF to determine the buffer size1142// SIOCGIFCOUNT doesn't work1143ifc.ifc_buf = NULL;1144if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {1145NET_ThrowByNameWithLastError1146(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");1147return ifs;1148}11491150// call SIOCGIFCONF to enumerate the interfaces1151CHECKED_MALLOC3(buf, char *, ifc.ifc_len);1152ifc.ifc_buf = buf;1153if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {1154NET_ThrowByNameWithLastError1155(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");1156free(buf);1157return ifs;1158}11591160// iterate through each interface1161ifreqP = ifc.ifc_req;1162for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {1163struct sockaddr addr, broadaddr, *broadaddrP = NULL;1164short prefix = 0;11651166// ignore non IPv4 addresses1167if (ifreqP->ifr_addr.sa_family != AF_INET) {1168continue;1169}11701171// save socket address1172memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));11731174// determine broadcast address, if applicable1175if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&1176ifreqP->ifr_flags & IFF_BROADCAST) {11771178// restore socket address to ifreqP1179memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));11801181if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {1182memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),1183sizeof(struct sockaddr));1184broadaddrP = &broadaddr;1185}1186}11871188// restore socket address to ifreqP1189memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));11901191// determine netmask1192if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {1193prefix = translateIPv4AddressToPrefix(1194(struct sockaddr_in *)&(ifreqP->ifr_netmask));1195}11961197// add interface to the list1198ifs = addif(env, sock, ifreqP->ifr_name, ifs,1199&addr, broadaddrP, AF_INET, prefix);12001201// in case of exception, free interface list and buffer and return NULL1202if ((*env)->ExceptionOccurred(env)) {1203free(buf);1204freeif(ifs);1205return NULL;1206}1207}12081209// free buffer1210free(buf);1211return ifs;1212}12131214#if defined(AF_INET6)12151216/*1217* Enumerates and returns all IPv6 interfaces on Linux.1218*/1219static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {1220FILE *f;1221char devname[21], addr6p[8][5];1222int prefix, scope, dad_status, if_idx;12231224if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {1225while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",1226addr6p[0], addr6p[1], addr6p[2], addr6p[3],1227addr6p[4], addr6p[5], addr6p[6], addr6p[7],1228&if_idx, &prefix, &scope, &dad_status, devname) != EOF) {12291230char addr6[40];1231struct sockaddr_in6 addr;12321233sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",1234addr6p[0], addr6p[1], addr6p[2], addr6p[3],1235addr6p[4], addr6p[5], addr6p[6], addr6p[7]);12361237memset(&addr, 0, sizeof(struct sockaddr_in6));1238inet_pton(AF_INET6, addr6, (void*)addr.sin6_addr.s6_addr);12391240// set scope ID to interface index1241addr.sin6_scope_id = if_idx;12421243// add interface to the list1244ifs = addif(env, sock, devname, ifs, (struct sockaddr *)&addr,1245NULL, AF_INET6, (short)prefix);12461247// if an exception occurred then return the list as is1248if ((*env)->ExceptionOccurred(env)) {1249break;1250}1251}1252fclose(f);1253}1254return ifs;1255}12561257#endif /* AF_INET6 */12581259/*1260* Try to get the interface index.1261*/1262static int getIndex(int sock, const char *name) {1263struct ifreq if2;1264memset((char *)&if2, 0, sizeof(if2));1265strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);12661267if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {1268return -1;1269}12701271return if2.ifr_ifindex;1272}12731274/*1275* Gets the Hardware address (usually MAC address) for the named interface.1276* On return puts the data in buf, and returns the length, in byte, of the1277* MAC address. Returns -1 if there is no hardware address on that interface.1278*/1279static int getMacAddress1280(JNIEnv *env, const char *ifname, const struct in_addr *addr,1281unsigned char *buf)1282{1283struct ifreq ifr;1284int i, sock;12851286if ((sock = openSocketWithFallback(env, ifname)) < 0) {1287return -1;1288}12891290memset((char *)&ifr, 0, sizeof(ifr));1291strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);1292if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {1293NET_ThrowByNameWithLastError1294(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFHWADDR) failed");1295close(sock);1296return -1;1297}12981299close(sock);1300memcpy(buf, &ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);13011302// all bytes to 0 means no hardware address1303for (i = 0; i < IFHWADDRLEN; i++) {1304if (buf[i] != 0)1305return IFHWADDRLEN;1306}13071308return -1;1309}13101311static int getMTU(JNIEnv *env, int sock, const char *ifname) {1312struct ifreq if2;1313memset((char *)&if2, 0, sizeof(if2));1314strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);13151316if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {1317NET_ThrowByNameWithLastError1318(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");1319return -1;1320}13211322return if2.ifr_mtu;1323}13241325static int getFlags(int sock, const char *ifname, int *flags) {1326struct ifreq if2;1327memset((char *)&if2, 0, sizeof(if2));1328strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);13291330if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {1331return -1;1332}13331334if (sizeof(if2.ifr_flags) == sizeof(short)) {1335*flags = (if2.ifr_flags & 0xffff);1336} else {1337*flags = if2.ifr_flags;1338}1339return 0;1340}13411342#endif /* __linux__ */13431344/** AIX **/1345#if defined(_AIX)13461347#if defined(AF_INET6)1348/*1349* Opens a socket for further ioctl calls. Tries AF_INET socket first and1350* if it fails return AF_INET6 socket.1351*/1352static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1353int sock;13541355if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {1356if (errno == EPROTONOSUPPORT) {1357if ((sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {1358NET_ThrowByNameWithLastError1359(env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");1360return -1;1361}1362} else { // errno is not NOSUPPORT1363NET_ThrowByNameWithLastError1364(env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");1365return -1;1366}1367}13681369return sock;1370}1371#else1372static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1373return openSocket(env, AF_INET);1374}1375#endif13761377/*1378* Enumerates and returns all IPv4 interfaces on AIX.1379*/1380static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {1381struct ifconf ifc;1382struct ifreq *ifreqP;1383char *buf = NULL;1384unsigned i;13851386// call SIOCGSIZIFCONF to get the size of SIOCGIFCONF buffer1387if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {1388NET_ThrowByNameWithLastError1389(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");1390return ifs;1391}13921393// call CSIOCGIFCONF instead of SIOCGIFCONF where interface1394// records will always have sizeof(struct ifreq) length.1395// Be aware that only IPv4 data is complete this way.1396CHECKED_MALLOC3(buf, char *, ifc.ifc_len);1397ifc.ifc_buf = buf;1398if (ioctl(sock, CSIOCGIFCONF, (char *)&ifc) < 0) {1399NET_ThrowByNameWithLastError1400(env, JNU_JAVANETPKG "SocketException", "ioctl(CSIOCGIFCONF) failed");1401free(buf);1402return ifs;1403}14041405// iterate through each interface1406ifreqP = ifc.ifc_req;1407for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++, ifreqP++) {1408struct sockaddr addr, broadaddr, *broadaddrP = NULL;1409short prefix = 0;14101411// ignore non IPv4 addresses1412if (ifreqP->ifr_addr.sa_family != AF_INET) {1413continue;1414}14151416// save socket address1417memcpy(&addr, &(ifreqP->ifr_addr), sizeof(struct sockaddr));14181419// determine broadcast address, if applicable1420if ((ioctl(sock, SIOCGIFFLAGS, ifreqP) == 0) &&1421ifreqP->ifr_flags & IFF_BROADCAST) {14221423// restore socket address to ifreqP1424memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));14251426if (ioctl(sock, SIOCGIFBRDADDR, ifreqP) == 0) {1427memcpy(&broadaddr, &(ifreqP->ifr_broadaddr),1428sizeof(struct sockaddr));1429broadaddrP = &broadaddr;1430}1431}14321433// restore socket address to ifreqP1434memcpy(&(ifreqP->ifr_addr), &addr, sizeof(struct sockaddr));14351436// determine netmask1437if (ioctl(sock, SIOCGIFNETMASK, ifreqP) == 0) {1438prefix = translateIPv4AddressToPrefix(1439(struct sockaddr_in *)&(ifreqP->ifr_addr));1440}14411442// add interface to the list1443ifs = addif(env, sock, ifreqP->ifr_name, ifs,1444&addr, broadaddrP, AF_INET, prefix);14451446// in case of exception, free interface list and buffer and return NULL1447if ((*env)->ExceptionOccurred(env)) {1448free(buf);1449freeif(ifs);1450return NULL;1451}1452}14531454// free buffer1455free(buf);1456return ifs;1457}14581459#if defined(AF_INET6)14601461/*1462* Enumerates and returns all IPv6 interfaces on AIX.1463*/1464static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {1465struct ifconf ifc;1466struct ifreq *ifreqP;1467char *buf, *cp, *cplimit;14681469// call SIOCGSIZIFCONF to get size for SIOCGIFCONF buffer1470if (ioctl(sock, SIOCGSIZIFCONF, &(ifc.ifc_len)) < 0) {1471NET_ThrowByNameWithLastError1472(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGSIZIFCONF) failed");1473return ifs;1474}14751476// call SIOCGIFCONF to enumerate the interfaces1477CHECKED_MALLOC3(buf, char *, ifc.ifc_len);1478ifc.ifc_buf = buf;1479if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {1480NET_ThrowByNameWithLastError1481(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFCONF) failed");1482free(buf);1483return ifs;1484}14851486// iterate through each interface1487ifreqP = ifc.ifc_req;1488cp = (char *)ifc.ifc_req;1489cplimit = cp + ifc.ifc_len;14901491for (; cp < cplimit;1492cp += (sizeof(ifreqP->ifr_name) +1493MAX((ifreqP->ifr_addr).sa_len, sizeof(ifreqP->ifr_addr))))1494{1495ifreqP = (struct ifreq *)cp;1496short prefix = 0;14971498// ignore non IPv6 addresses1499if (ifreqP->ifr_addr.sa_family != AF_INET6) {1500continue;1501}15021503// determine netmask1504struct in6_ifreq if6;1505memset((char *)&if6, 0, sizeof(if6));1506strncpy(if6.ifr_name, ifreqP->ifr_name, sizeof(if6.ifr_name) - 1);1507memcpy(&(if6.ifr_Addr), &(ifreqP->ifr_addr),1508sizeof(struct sockaddr_in6));1509if (ioctl(sock, SIOCGIFNETMASK6, (char *)&if6) >= 0) {1510prefix = translateIPv6AddressToPrefix(&(if6.ifr_Addr));1511}15121513// set scope ID to interface index1514((struct sockaddr_in6 *)&(ifreqP->ifr_addr))->sin6_scope_id =1515getIndex(sock, ifreqP->ifr_name);15161517// add interface to the list1518ifs = addif(env, sock, ifreqP->ifr_name, ifs,1519(struct sockaddr *)&(ifreqP->ifr_addr),1520NULL, AF_INET6, prefix);15211522// if an exception occurred then free the list1523if ((*env)->ExceptionOccurred(env)) {1524free(buf);1525freeif(ifs);1526return NULL;1527}1528}15291530// free buffer1531free(buf);1532return ifs;1533}15341535#endif /* AF_INET6 */15361537/*1538* Try to get the interface index.1539*/1540static int getIndex(int sock, const char *name) {1541int index = if_nametoindex(name);1542return (index == 0) ? -1 : index;1543}15441545/*1546* Gets the Hardware address (usually MAC address) for the named interface.1547* On return puts the data in buf, and returns the length, in byte, of the1548* MAC address. Returns -1 if there is no hardware address on that interface.1549*/1550static int getMacAddress1551(JNIEnv *env, const char *ifname, const struct in_addr *addr,1552unsigned char *buf)1553{1554int size;1555struct kinfo_ndd *nddp;1556void *end;15571558size = getkerninfo(KINFO_NDD, 0, 0, 0);1559if (size == 0) {1560return -1;1561}15621563if (size < 0) {1564perror("getkerninfo 1");1565return -1;1566}15671568nddp = (struct kinfo_ndd *)malloc(size);15691570if (!nddp) {1571JNU_ThrowOutOfMemoryError(env,1572"Network interface getMacAddress native buffer allocation failed");1573return -1;1574}15751576if (getkerninfo(KINFO_NDD, nddp, &size, 0) < 0) {1577perror("getkerninfo 2");1578return -1;1579}15801581end = (void *)nddp + size;1582while ((void *)nddp < end) {1583if (!strcmp(nddp->ndd_alias, ifname) ||1584!strcmp(nddp->ndd_name, ifname)) {1585bcopy(nddp->ndd_addr, buf, 6);1586return 6;1587} else {1588nddp++;1589}1590}15911592return -1;1593}15941595static int getMTU(JNIEnv *env, int sock, const char *ifname) {1596struct ifreq if2;1597memset((char *)&if2, 0, sizeof(if2));1598strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);15991600if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {1601NET_ThrowByNameWithLastError1602(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");1603return -1;1604}16051606return if2.ifr_mtu;1607}16081609static int getFlags(int sock, const char *ifname, int *flags) {1610struct ifreq if2;1611memset((char *)&if2, 0, sizeof(if2));1612strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);16131614if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {1615return -1;1616}16171618if (sizeof(if2.ifr_flags) == sizeof(short)) {1619*flags = (if2.ifr_flags & 0xffff);1620} else {1621*flags = if2.ifr_flags;1622}1623return 0;1624}16251626#endif /* _AIX */16271628/** Solaris **/1629#if defined(__solaris__)16301631#if defined(AF_INET6)1632/*1633* Opens a socket for further ioctl calls. Tries AF_INET socket first and1634* if it fails return AF_INET6 socket.1635*/1636static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1637int sock, alreadyV6 = 0;1638struct lifreq if2;16391640if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {1641if (errno == EPROTONOSUPPORT) {1642if ((sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {1643NET_ThrowByNameWithLastError1644(env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");1645return -1;1646}1647alreadyV6 = 1;1648} else { // errno is not NOSUPPORT1649NET_ThrowByNameWithLastError1650(env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");1651return -1;1652}1653}16541655// Solaris requires that we have an IPv6 socket to query an interface1656// without an IPv4 address - check it here. POSIX 1 require the kernel to1657// return ENOTTY if the call is inappropriate for a device e.g. the NETMASK1658// for a device having IPv6 only address but not all devices follow the1659// standard so fall back on any error. It's not an ecologically friendly1660// gesture but more reliable.1661if (!alreadyV6) {1662memset((char *)&if2, 0, sizeof(if2));1663strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);1664if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {1665close(sock);1666if ((sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {1667NET_ThrowByNameWithLastError1668(env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");1669return -1;1670}1671}1672}16731674return sock;1675}1676#else1677static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1678return openSocket(env, AF_INET);1679}1680#endif16811682/*1683* Enumerates and returns all IPv4 interfaces on Solaris.1684*/1685static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {1686struct lifconf ifc;1687struct lifreq *ifreqP;1688struct lifnum numifs;1689char *buf = NULL;1690unsigned i;16911692// call SIOCGLIFNUM to get the interface count1693numifs.lifn_family = AF_INET;1694numifs.lifn_flags = 0;1695if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {1696NET_ThrowByNameWithLastError1697(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFNUM) failed");1698return ifs;1699}17001701// call SIOCGLIFCONF to enumerate the interfaces1702ifc.lifc_len = numifs.lifn_count * sizeof(struct lifreq);1703CHECKED_MALLOC3(buf, char *, ifc.lifc_len);1704ifc.lifc_buf = buf;1705ifc.lifc_family = AF_INET;1706ifc.lifc_flags = 0;1707if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {1708NET_ThrowByNameWithLastError1709(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFCONF) failed");1710free(buf);1711return ifs;1712}17131714// iterate through each interface1715ifreqP = ifc.lifc_req;1716for (i = 0; i < numifs.lifn_count; i++, ifreqP++) {1717struct sockaddr addr, *broadaddrP = NULL;17181719// ignore non IPv4 addresses1720if (ifreqP->lifr_addr.ss_family != AF_INET) {1721continue;1722}17231724// save socket address1725memcpy(&addr, &(ifreqP->lifr_addr), sizeof(struct sockaddr));17261727// determine broadcast address, if applicable1728if ((ioctl(sock, SIOCGLIFFLAGS, ifreqP) == 0) &&1729ifreqP->lifr_flags & IFF_BROADCAST) {17301731// restore socket address to ifreqP1732memcpy(&(ifreqP->lifr_addr), &addr, sizeof(struct sockaddr));17331734// query broadcast address and set pointer to it1735if (ioctl(sock, SIOCGLIFBRDADDR, ifreqP) == 0) {1736broadaddrP = (struct sockaddr *)&(ifreqP->lifr_broadaddr);1737}1738}17391740// add to the list1741ifs = addif(env, sock, ifreqP->lifr_name, ifs,1742&addr, broadaddrP, AF_INET, (short)ifreqP->lifr_addrlen);17431744// if an exception occurred we return immediately1745if ((*env)->ExceptionOccurred(env)) {1746free(buf);1747return ifs;1748}1749}17501751// free buffer1752free(buf);1753return ifs;1754}17551756#if defined(AF_INET6)17571758/*1759* Enumerates and returns all IPv6 interfaces on Solaris.1760*/1761static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {1762struct lifconf ifc;1763struct lifreq *ifreqP;1764struct lifnum numifs;1765char *buf = NULL;1766unsigned i;17671768// call SIOCGLIFNUM to get the interface count1769numifs.lifn_family = AF_INET6;1770numifs.lifn_flags = 0;1771if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {1772NET_ThrowByNameWithLastError1773(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFNUM) failed");1774return ifs;1775}17761777// call SIOCGLIFCONF to enumerate the interfaces1778ifc.lifc_len = numifs.lifn_count * sizeof(struct lifreq);1779CHECKED_MALLOC3(buf, char *, ifc.lifc_len);1780ifc.lifc_buf = buf;1781ifc.lifc_family = AF_INET6;1782ifc.lifc_flags = 0;1783if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {1784NET_ThrowByNameWithLastError1785(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFCONF) failed");1786free(buf);1787return ifs;1788}17891790// iterate through each interface1791ifreqP = ifc.lifc_req;1792for (i = 0; i < numifs.lifn_count; i++, ifreqP++) {17931794// ignore non IPv6 addresses1795if (ifreqP->lifr_addr.ss_family != AF_INET6) {1796continue;1797}17981799// set scope ID to interface index1800((struct sockaddr_in6 *)&(ifreqP->lifr_addr))->sin6_scope_id =1801getIndex(sock, ifreqP->lifr_name);18021803// add to the list1804ifs = addif(env, sock, ifreqP->lifr_name, ifs,1805(struct sockaddr *)&(ifreqP->lifr_addr),1806NULL, AF_INET6, (short)ifreqP->lifr_addrlen);18071808// if an exception occurred we return immediately1809if ((*env)->ExceptionOccurred(env)) {1810free(buf);1811return ifs;1812}1813}18141815// free buffer1816free(buf);1817return ifs;1818}18191820#endif /* AF_INET6 */18211822/*1823* Try to get the interface index.1824* (Not supported on Solaris 2.6 or 7)1825*/1826static int getIndex(int sock, const char *name) {1827struct lifreq if2;1828memset((char *)&if2, 0, sizeof(if2));1829strncpy(if2.lifr_name, name, sizeof(if2.lifr_name) - 1);18301831if (ioctl(sock, SIOCGLIFINDEX, (char *)&if2) < 0) {1832return -1;1833}18341835return if2.lifr_index;1836}18371838/*1839* Solaris specific DLPI code to get hardware address from a device.1840* Unfortunately, at least up to Solaris X, you have to have special1841* privileges (i.e. be root).1842*/1843static int getMacFromDevice1844(JNIEnv *env, const char *ifname, unsigned char *retbuf)1845{1846char style1dev[MAXPATHLEN];1847int fd;1848dl_phys_addr_req_t dlpareq;1849dl_phys_addr_ack_t *dlpaack;1850struct strbuf msg;1851char buf[128];1852int flags = 0;18531854// Device is in /dev. e.g.: /dev/bge01855strcpy(style1dev, DEV_PREFIX);1856strcat(style1dev, ifname);1857if ((fd = open(style1dev, O_RDWR)) < 0) {1858// Can't open it. We probably are missing the privilege.1859// We'll have to try something else1860return 0;1861}18621863dlpareq.dl_primitive = DL_PHYS_ADDR_REQ;1864dlpareq.dl_addr_type = DL_CURR_PHYS_ADDR;18651866msg.buf = (char *)&dlpareq;1867msg.len = DL_PHYS_ADDR_REQ_SIZE;18681869if (putmsg(fd, &msg, NULL, 0) < 0) {1870NET_ThrowByNameWithLastError1871(env, JNU_JAVANETPKG "SocketException", "putmsg() failed");1872return -1;1873}18741875dlpaack = (dl_phys_addr_ack_t *)buf;18761877msg.buf = (char *)buf;1878msg.len = 0;1879msg.maxlen = sizeof (buf);1880if (getmsg(fd, &msg, NULL, &flags) < 0) {1881NET_ThrowByNameWithLastError1882(env, JNU_JAVANETPKG "SocketException", "getmsg() failed");1883return -1;1884}18851886if (msg.len < DL_PHYS_ADDR_ACK_SIZE || dlpaack->dl_primitive != DL_PHYS_ADDR_ACK) {1887JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",1888"Couldn't obtain phys addr\n");1889return -1;1890}18911892memcpy(retbuf, &buf[dlpaack->dl_addr_offset], dlpaack->dl_addr_length);1893return dlpaack->dl_addr_length;1894}18951896/*1897* Gets the Hardware address (usually MAC address) for the named interface.1898* On return puts the data in buf, and returns the length, in byte, of the1899* MAC address. Returns -1 if there is no hardware address on that interface.1900*/1901static int getMacAddress1902(JNIEnv *env, const char *ifname, const struct in_addr *addr,1903unsigned char *buf)1904{1905struct lifreq if2;1906int len, i, sock;19071908if ((sock = openSocketWithFallback(env, ifname)) < 0) {1909return -1;1910}19111912// First, try the new (S11) SIOCGLIFHWADDR ioctl(). If that fails1913// try the old way.1914memset((char *)&if2, 0, sizeof(if2));1915strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);19161917if (ioctl(sock, SIOCGLIFHWADDR, &if2) != -1) {1918struct sockaddr_dl *sp;1919sp = (struct sockaddr_dl *)&if2.lifr_addr;1920memcpy(buf, &sp->sdl_data[0], sp->sdl_alen);1921close(sock);1922return sp->sdl_alen;1923}19241925// On Solaris we have to use DLPI, but it will only work if we have1926// privileged access (i.e. root). If that fails, we try a lookup1927// in the ARP table, which requires an IPv4 address.1928if (((len = getMacFromDevice(env, ifname, buf)) == 0) && (addr != NULL)) {1929struct arpreq arpreq;1930struct sockaddr_in *sin;1931struct sockaddr_in ipAddr;19321933len = 6; //???19341935sin = (struct sockaddr_in *)&arpreq.arp_pa;1936memset((char *)&arpreq, 0, sizeof(struct arpreq));1937ipAddr.sin_port = 0;1938ipAddr.sin_family = AF_INET;1939memcpy(&ipAddr.sin_addr, addr, sizeof(struct in_addr));1940memcpy(&arpreq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));1941arpreq.arp_flags= ATF_PUBL;19421943if (ioctl(sock, SIOCGARP, &arpreq) < 0) {1944close(sock);1945return -1;1946}19471948memcpy(buf, &arpreq.arp_ha.sa_data[0], len);1949}1950close(sock);19511952// all bytes to 0 means no hardware address1953for (i = 0; i < len; i++) {1954if (buf[i] != 0)1955return len;1956}19571958return -1;1959}19601961static int getMTU(JNIEnv *env, int sock, const char *ifname) {1962struct lifreq if2;1963memset((char *)&if2, 0, sizeof(if2));1964strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);19651966if (ioctl(sock, SIOCGLIFMTU, (char *)&if2) < 0) {1967NET_ThrowByNameWithLastError1968(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFMTU) failed");1969return -1;1970}19711972return if2.lifr_mtu;1973}19741975static int getFlags(int sock, const char *ifname, int *flags) {1976struct lifreq if2;1977memset((char *)&if2, 0, sizeof(if2));1978strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);19791980if (ioctl(sock, SIOCGLIFFLAGS, (char *)&if2) < 0) {1981return -1;1982}19831984*flags = if2.lifr_flags;1985return 0;1986}19871988#endif /* __solaris__ */19891990/** BSD **/1991#if defined(_ALLBSD_SOURCE)19921993#if defined(AF_INET6)1994/*1995* Opens a socket for further ioctl calls. Tries AF_INET socket first and1996* if it fails return AF_INET6 socket.1997*/1998static int openSocketWithFallback(JNIEnv *env, const char *ifname) {1999int sock;20002001if ((sock = JVM_Socket(AF_INET, SOCK_DGRAM, 0)) < 0) {2002if (errno == EPROTONOSUPPORT) {2003if ((sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {2004NET_ThrowByNameWithLastError2005(env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");2006return -1;2007}2008} else { // errno is not NOSUPPORT2009NET_ThrowByNameWithLastError2010(env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");2011return -1;2012}2013}20142015return sock;2016}2017#else2018static int openSocketWithFallback(JNIEnv *env, const char *ifname) {2019return openSocket(env, AF_INET);2020}2021#endif20222023/*2024* Enumerates and returns all IPv4 interfaces on BSD.2025*/2026static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {2027struct ifaddrs *ifa, *origifa;20282029if (getifaddrs(&origifa) != 0) {2030NET_ThrowByNameWithLastError2031(env, JNU_JAVANETPKG "SocketException", "getifaddrs() failed");2032return ifs;2033}20342035for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {2036struct sockaddr *broadaddrP = NULL;20372038// ignore non IPv4 addresses2039if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)2040continue;20412042// set ifa_broadaddr, if there is one2043if ((ifa->ifa_flags & IFF_POINTOPOINT) == 0 &&2044ifa->ifa_flags & IFF_BROADCAST) {2045broadaddrP = ifa->ifa_dstaddr;2046}20472048// add interface to the list2049ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr,2050broadaddrP, AF_INET,2051translateIPv4AddressToPrefix((struct sockaddr_in *)2052ifa->ifa_netmask));20532054// if an exception occurred then free the list2055if ((*env)->ExceptionOccurred(env)) {2056freeifaddrs(origifa);2057freeif(ifs);2058return NULL;2059}2060}20612062// free ifaddrs buffer2063freeifaddrs(origifa);2064return ifs;2065}20662067#if defined(AF_INET6)20682069/*2070* Enumerates and returns all IPv6 interfaces on BSD.2071*/2072static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {2073struct ifaddrs *ifa, *origifa;20742075if (getifaddrs(&origifa) != 0) {2076NET_ThrowByNameWithLastError2077(env, JNU_JAVANETPKG "SocketException", "getifaddrs() failed");2078return ifs;2079}20802081for (ifa = origifa; ifa != NULL; ifa = ifa->ifa_next) {2082// ignore non IPv6 addresses2083if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET6)2084continue;20852086// set scope ID to interface index2087((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id =2088getIndex(sock, ifa->ifa_name);20892090// add interface to the list2091ifs = addif(env, sock, ifa->ifa_name, ifs, ifa->ifa_addr, NULL,2092AF_INET6,2093translateIPv6AddressToPrefix((struct sockaddr_in6 *)2094ifa->ifa_netmask));20952096// if an exception occurred then free the list2097if ((*env)->ExceptionOccurred(env)) {2098freeifaddrs(origifa);2099freeif(ifs);2100return NULL;2101}2102}21032104// free ifaddrs buffer2105freeifaddrs(origifa);2106return ifs;2107}21082109#endif /* AF_INET6 */21102111/*2112* Try to get the interface index.2113*/2114static int getIndex(int sock, const char *name) {2115#if !defined(__FreeBSD__)2116int index = if_nametoindex(name);2117return (index == 0) ? -1 : index;2118#else2119struct ifreq if2;2120memset((char *)&if2, 0, sizeof(if2));2121strncpy(if2.ifr_name, name, sizeof(if2.ifr_name) - 1);21222123if (ioctl(sock, SIOCGIFINDEX, (char *)&if2) < 0) {2124return -1;2125}21262127return if2.ifr_index;2128#endif2129}21302131/*2132* Gets the Hardware address (usually MAC address) for the named interface.2133* On return puts the data in buf, and returns the length, in byte, of the2134* MAC address. Returns -1 if there is no hardware address on that interface.2135*/2136static int getMacAddress2137(JNIEnv *env, const char *ifname, const struct in_addr *addr,2138unsigned char *buf)2139{2140struct ifaddrs *ifa0, *ifa;2141struct sockaddr *saddr;2142int i;21432144// grab the interface list2145if (!getifaddrs(&ifa0)) {2146// cycle through the interfaces2147for (i = 0, ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next, i++) {2148saddr = ifa->ifa_addr;2149// link layer contains the MAC address2150if (saddr->sa_family == AF_LINK && !strcmp(ifname, ifa->ifa_name)) {2151struct sockaddr_dl *sadl = (struct sockaddr_dl *) saddr;2152// check the address has the correct length2153if (sadl->sdl_alen == ETHER_ADDR_LEN) {2154memcpy(buf, (sadl->sdl_data + sadl->sdl_nlen), ETHER_ADDR_LEN);2155freeifaddrs(ifa0);2156return ETHER_ADDR_LEN;2157}2158}2159}2160freeifaddrs(ifa0);2161}21622163return -1;2164}21652166static int getMTU(JNIEnv *env, int sock, const char *ifname) {2167struct ifreq if2;2168memset((char *)&if2, 0, sizeof(if2));2169strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);21702171if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) {2172NET_ThrowByNameWithLastError2173(env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGIFMTU) failed");2174return -1;2175}21762177return if2.ifr_mtu;2178}21792180static int getFlags(int sock, const char *ifname, int *flags) {2181struct ifreq if2;2182memset((char *)&if2, 0, sizeof(if2));2183strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1);21842185if (ioctl(sock, SIOCGIFFLAGS, (char *)&if2) < 0) {2186return -1;2187}21882189if (sizeof(if2.ifr_flags) == sizeof(short)) {2190*flags = (if2.ifr_flags & 0xffff);2191} else {2192*flags = if2.ifr_flags;2193}2194return 0;2195}2196#endif /* _ALLBSD_SOURCE */219721982199