| /* Copyright (C) 2003,2006,2011 Juan Lang | 
 |  * | 
 |  * This library is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU Lesser General Public | 
 |  * License as published by the Free Software Foundation; either | 
 |  * version 2.1 of the License, or (at your option) any later version. | 
 |  * | 
 |  * This library is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * Lesser General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU Lesser General Public | 
 |  * License along with this library; if not, write to the Free Software | 
 |  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
 |  */ | 
 |  | 
 | #include "config.h" | 
 |  | 
 | #include <stdarg.h> | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 |  | 
 | #ifdef HAVE_UNISTD_H | 
 | #include <unistd.h> | 
 | #endif | 
 |  | 
 | #include <sys/types.h> | 
 | #ifdef HAVE_SYS_PARAM_H | 
 | #include <sys/param.h> | 
 | #endif | 
 |  | 
 | #ifdef HAVE_SYS_SOCKET_H | 
 | #include <sys/socket.h> | 
 | #endif | 
 |  | 
 | #ifdef HAVE_NETINET_IN_H | 
 | #include <netinet/in.h> | 
 | #endif | 
 |  | 
 | #ifdef HAVE_ARPA_INET_H | 
 | #include <arpa/inet.h> | 
 | #endif | 
 |  | 
 | #ifdef HAVE_NET_IF_H | 
 | #include <net/if.h> | 
 | #endif | 
 |  | 
 | #ifdef HAVE_NET_IF_ARP_H | 
 | #include <net/if_arp.h> | 
 | #endif | 
 |  | 
 | #ifdef HAVE_NET_ROUTE_H | 
 | #include <net/route.h> | 
 | #endif | 
 |  | 
 | #ifdef HAVE_SYS_IOCTL_H | 
 | #include <sys/ioctl.h> | 
 | #endif | 
 |  | 
 | #ifdef HAVE_SYS_SYSCTL_H | 
 | #include <sys/sysctl.h> | 
 | #endif | 
 |  | 
 | #ifdef HAVE_SYS_SOCKIO_H | 
 | #include <sys/sockio.h> | 
 | #endif | 
 |  | 
 | #ifdef HAVE_NET_IF_DL_H | 
 | #include <net/if_dl.h> | 
 | #endif | 
 |  | 
 | #ifdef HAVE_NET_IF_TYPES_H | 
 | #include <net/if_types.h> | 
 | #endif | 
 |  | 
 | #ifdef HAVE_IFADDRS_H | 
 | #include <ifaddrs.h> | 
 | #endif | 
 |  | 
 | #include "ifenum.h" | 
 | #include "ws2ipdef.h" | 
 |  | 
 | #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN | 
 | #define ifreq_len(ifr) \ | 
 |  max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len) | 
 | #else | 
 | #define ifreq_len(ifr) sizeof(struct ifreq) | 
 | #endif | 
 |  | 
 | #ifndef ETH_ALEN | 
 | #define ETH_ALEN 6 | 
 | #endif | 
 |  | 
 | #ifndef IF_NAMESIZE | 
 | #define IF_NAMESIZE 16 | 
 | #endif | 
 |  | 
 | #ifndef INADDR_NONE | 
 | #define INADDR_NONE (~0U) | 
 | #endif | 
 |  | 
 | #define INITIAL_INTERFACES_ASSUMED 4 | 
 |  | 
 | /* Functions */ | 
 |  | 
 | static int isLoopbackInterface(int fd, const char *name) | 
 | { | 
 |   int ret = 0; | 
 |  | 
 |   if (name) { | 
 |     struct ifreq ifr; | 
 |  | 
 |     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); | 
 |     if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0) | 
 |       ret = ifr.ifr_flags & IFF_LOOPBACK; | 
 |   } | 
 |   return ret; | 
 | } | 
 |  | 
 | /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE | 
 |  * bytes are necessary. | 
 |  */ | 
 | char *getInterfaceNameByIndex(IF_INDEX index, char *name) | 
 | { | 
 |   return if_indextoname(index, name); | 
 | } | 
 |  | 
 | DWORD getInterfaceIndexByName(const char *name, IF_INDEX *index) | 
 | { | 
 |   DWORD ret; | 
 |   unsigned int idx; | 
 |  | 
 |   if (!name) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |   if (!index) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |   idx = if_nametoindex(name); | 
 |   if (idx) { | 
 |     *index = idx; | 
 |     ret = NO_ERROR; | 
 |   } | 
 |   else | 
 |     ret = ERROR_INVALID_DATA; | 
 |   return ret; | 
 | } | 
 |  | 
 | BOOL isIfIndexLoopback(ULONG idx) | 
 | { | 
 |   BOOL ret = FALSE; | 
 |   char name[IFNAMSIZ]; | 
 |   int fd; | 
 |  | 
 |   getInterfaceNameByIndex(idx, name); | 
 |   fd = socket(PF_INET, SOCK_DGRAM, 0); | 
 |   if (fd != -1) { | 
 |     ret = isLoopbackInterface(fd, name); | 
 |     close(fd); | 
 |   } | 
 |   return ret; | 
 | } | 
 |  | 
 | DWORD getNumNonLoopbackInterfaces(void) | 
 | { | 
 |   DWORD numInterfaces; | 
 |   int fd = socket(PF_INET, SOCK_DGRAM, 0); | 
 |  | 
 |   if (fd != -1) { | 
 |     struct if_nameindex *indexes = if_nameindex(); | 
 |  | 
 |     if (indexes) { | 
 |       struct if_nameindex *p; | 
 |  | 
 |       for (p = indexes, numInterfaces = 0; p && p->if_name; p++) | 
 |         if (!isLoopbackInterface(fd, p->if_name)) | 
 |           numInterfaces++; | 
 |       if_freenameindex(indexes); | 
 |     } | 
 |     else | 
 |       numInterfaces = 0; | 
 |     close(fd); | 
 |   } | 
 |   else | 
 |     numInterfaces = 0; | 
 |   return numInterfaces; | 
 | } | 
 |  | 
 | DWORD getNumInterfaces(void) | 
 | { | 
 |   DWORD numInterfaces; | 
 |   struct if_nameindex *indexes = if_nameindex(); | 
 |  | 
 |   if (indexes) { | 
 |     struct if_nameindex *p; | 
 |  | 
 |     for (p = indexes, numInterfaces = 0; p && p->if_name; p++) | 
 |       numInterfaces++; | 
 |     if_freenameindex(indexes); | 
 |   } | 
 |   else | 
 |     numInterfaces = 0; | 
 |   return numInterfaces; | 
 | } | 
 |  | 
 | InterfaceIndexTable *getInterfaceIndexTable(void) | 
 | { | 
 |   DWORD numInterfaces; | 
 |   InterfaceIndexTable *ret; | 
 |   struct if_nameindex *indexes = if_nameindex(); | 
 |  | 
 |   if (indexes) { | 
 |     struct if_nameindex *p; | 
 |     DWORD size = sizeof(InterfaceIndexTable); | 
 |  | 
 |     for (p = indexes, numInterfaces = 0; p && p->if_name; p++) | 
 |       numInterfaces++; | 
 |     if (numInterfaces > 1) | 
 |       size += (numInterfaces - 1) * sizeof(DWORD); | 
 |     ret = HeapAlloc(GetProcessHeap(), 0, size); | 
 |     if (ret) { | 
 |       ret->numIndexes = 0; | 
 |       for (p = indexes; p && p->if_name; p++) | 
 |         ret->indexes[ret->numIndexes++] = p->if_index; | 
 |     } | 
 |     if_freenameindex(indexes); | 
 |   } | 
 |   else | 
 |     ret = NULL; | 
 |   return ret; | 
 | } | 
 |  | 
 | InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void) | 
 | { | 
 |   DWORD numInterfaces; | 
 |   InterfaceIndexTable *ret; | 
 |   int fd = socket(PF_INET, SOCK_DGRAM, 0); | 
 |  | 
 |   if (fd != -1) { | 
 |     struct if_nameindex *indexes = if_nameindex(); | 
 |  | 
 |     if (indexes) { | 
 |       struct if_nameindex *p; | 
 |       DWORD size = sizeof(InterfaceIndexTable); | 
 |  | 
 |       for (p = indexes, numInterfaces = 0; p && p->if_name; p++) | 
 |         if (!isLoopbackInterface(fd, p->if_name)) | 
 |           numInterfaces++; | 
 |       if (numInterfaces > 1) | 
 |         size += (numInterfaces - 1) * sizeof(DWORD); | 
 |       ret = HeapAlloc(GetProcessHeap(), 0, size); | 
 |       if (ret) { | 
 |         ret->numIndexes = 0; | 
 |         for (p = indexes; p && p->if_name; p++) | 
 |           if (!isLoopbackInterface(fd, p->if_name)) | 
 |             ret->indexes[ret->numIndexes++] = p->if_index; | 
 |       } | 
 |       if_freenameindex(indexes); | 
 |     } | 
 |     else | 
 |       ret = NULL; | 
 |     close(fd); | 
 |   } | 
 |   else | 
 |     ret = NULL; | 
 |   return ret; | 
 | } | 
 |  | 
 | static DWORD getInterfaceBCastAddrByName(const char *name) | 
 | { | 
 |   DWORD ret = INADDR_ANY; | 
 |  | 
 |   if (name) { | 
 |     int fd = socket(PF_INET, SOCK_DGRAM, 0); | 
 |  | 
 |     if (fd != -1) { | 
 |       struct ifreq ifr; | 
 |  | 
 |       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); | 
 |       if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0) | 
 |         memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD)); | 
 |       close(fd); | 
 |     } | 
 |   } | 
 |   return ret; | 
 | } | 
 |  | 
 | static DWORD getInterfaceMaskByName(const char *name) | 
 | { | 
 |   DWORD ret = INADDR_NONE; | 
 |  | 
 |   if (name) { | 
 |     int fd = socket(PF_INET, SOCK_DGRAM, 0); | 
 |  | 
 |     if (fd != -1) { | 
 |       struct ifreq ifr; | 
 |  | 
 |       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); | 
 |       if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0) | 
 |         memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD)); | 
 |       close(fd); | 
 |     } | 
 |   } | 
 |   return ret; | 
 | } | 
 |  | 
 | #if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR) | 
 | static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr, | 
 |  PDWORD type) | 
 | { | 
 |   DWORD ret; | 
 |   int fd; | 
 |  | 
 |   if (!name || !len || !addr || !type) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |  | 
 |   fd = socket(PF_INET, SOCK_DGRAM, 0); | 
 |   if (fd != -1) { | 
 |     struct ifreq ifr; | 
 |  | 
 |     memset(&ifr, 0, sizeof(struct ifreq)); | 
 |     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); | 
 |     if ((ioctl(fd, SIOCGIFHWADDR, &ifr))) | 
 |       ret = ERROR_INVALID_DATA; | 
 |     else { | 
 |       unsigned int addrLen; | 
 |  | 
 |       switch (ifr.ifr_hwaddr.sa_family) | 
 |       { | 
 | #ifdef ARPHRD_LOOPBACK | 
 |         case ARPHRD_LOOPBACK: | 
 |           addrLen = 0; | 
 |           *type = MIB_IF_TYPE_LOOPBACK; | 
 |           break; | 
 | #endif | 
 | #ifdef ARPHRD_ETHER | 
 |         case ARPHRD_ETHER: | 
 |           addrLen = ETH_ALEN; | 
 |           *type = MIB_IF_TYPE_ETHERNET; | 
 |           break; | 
 | #endif | 
 | #ifdef ARPHRD_FDDI | 
 |         case ARPHRD_FDDI: | 
 |           addrLen = ETH_ALEN; | 
 |           *type = MIB_IF_TYPE_FDDI; | 
 |           break; | 
 | #endif | 
 | #ifdef ARPHRD_IEEE802 | 
 |         case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */ | 
 |           addrLen = ETH_ALEN; | 
 |           *type = MIB_IF_TYPE_TOKENRING; | 
 |           break; | 
 | #endif | 
 | #ifdef ARPHRD_IEEE802_TR | 
 |         case ARPHRD_IEEE802_TR: /* also Token Ring? */ | 
 |           addrLen = ETH_ALEN; | 
 |           *type = MIB_IF_TYPE_TOKENRING; | 
 |           break; | 
 | #endif | 
 | #ifdef ARPHRD_SLIP | 
 |         case ARPHRD_SLIP: | 
 |           addrLen = 0; | 
 |           *type = MIB_IF_TYPE_SLIP; | 
 |           break; | 
 | #endif | 
 | #ifdef ARPHRD_PPP | 
 |         case ARPHRD_PPP: | 
 |           addrLen = 0; | 
 |           *type = MIB_IF_TYPE_PPP; | 
 |           break; | 
 | #endif | 
 |         default: | 
 |           addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data)); | 
 |           *type = MIB_IF_TYPE_OTHER; | 
 |       } | 
 |       if (addrLen > *len) { | 
 |         ret = ERROR_INSUFFICIENT_BUFFER; | 
 |         *len = addrLen; | 
 |       } | 
 |       else { | 
 |         if (addrLen > 0) | 
 |           memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen); | 
 |         /* zero out remaining bytes for broken implementations */ | 
 |         memset(addr + addrLen, 0, *len - addrLen); | 
 |         *len = addrLen; | 
 |         ret = NO_ERROR; | 
 |       } | 
 |     } | 
 |     close(fd); | 
 |   } | 
 |   else | 
 |     ret = ERROR_NO_MORE_FILES; | 
 |   return ret; | 
 | } | 
 | #elif defined (SIOCGARP) | 
 | static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr, | 
 |  PDWORD type) | 
 | { | 
 |   DWORD ret; | 
 |   int fd; | 
 |  | 
 |   if (!name || !len || !addr || !type) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |  | 
 |   fd = socket(PF_INET, SOCK_DGRAM, 0); | 
 |   if (fd != -1) { | 
 |     if (isLoopbackInterface(fd, name)) { | 
 |       *type = MIB_IF_TYPE_LOOPBACK; | 
 |       memset(addr, 0, *len); | 
 |       *len = 0; | 
 |       ret=NOERROR; | 
 |     } | 
 |     else { | 
 |       struct arpreq arp; | 
 |       struct sockaddr_in *saddr; | 
 |       struct ifreq ifr; | 
 |  | 
 |       /* get IP addr */ | 
 |       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); | 
 |       ioctl(fd, SIOCGIFADDR, &ifr); | 
 |       memset(&arp, 0, sizeof(struct arpreq)); | 
 |       arp.arp_pa.sa_family = AF_INET; | 
 |       saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */ | 
 |       saddr->sin_family = AF_INET; | 
 |       memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD)); | 
 |       if ((ioctl(fd, SIOCGARP, &arp))) | 
 |         ret = ERROR_INVALID_DATA; | 
 |       else { | 
 |         /* FIXME:  heh:  who said it was ethernet? */ | 
 |         int addrLen = ETH_ALEN; | 
 |  | 
 |         if (addrLen > *len) { | 
 |           ret = ERROR_INSUFFICIENT_BUFFER; | 
 |           *len = addrLen; | 
 |         } | 
 |         else { | 
 |           if (addrLen > 0) | 
 |             memcpy(addr, &arp.arp_ha.sa_data[0], addrLen); | 
 |           /* zero out remaining bytes for broken implementations */ | 
 |           memset(addr + addrLen, 0, *len - addrLen); | 
 |           *len = addrLen; | 
 |           *type = MIB_IF_TYPE_ETHERNET; | 
 |           ret = NO_ERROR; | 
 |         } | 
 |       } | 
 |     } | 
 |     close(fd); | 
 |   } | 
 |     else | 
 |       ret = ERROR_NO_MORE_FILES; | 
 |  | 
 |   return ret; | 
 | } | 
 | #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H) | 
 | static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr, | 
 |  PDWORD type) | 
 | { | 
 |   DWORD ret; | 
 |   struct if_msghdr *ifm; | 
 |   struct sockaddr_dl *sdl; | 
 |   u_char *p, *buf; | 
 |   size_t mibLen; | 
 |   int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 }; | 
 |   unsigned addrLen; | 
 |   BOOL found = FALSE; | 
 |  | 
 |   if (!name || !len || !addr || !type) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |  | 
 |   if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0) | 
 |     return ERROR_NO_MORE_FILES; | 
 |  | 
 |   buf = HeapAlloc(GetProcessHeap(), 0, mibLen); | 
 |   if (!buf) | 
 |     return ERROR_NOT_ENOUGH_MEMORY; | 
 |  | 
 |   if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) { | 
 |     HeapFree(GetProcessHeap(), 0, buf); | 
 |     return ERROR_NO_MORE_FILES; | 
 |   } | 
 |  | 
 |   ret = ERROR_INVALID_DATA; | 
 |   for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) { | 
 |     ifm = (struct if_msghdr *)p; | 
 |     sdl = (struct sockaddr_dl *)(ifm + 1); | 
 |  | 
 |     if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0) | 
 |       continue; | 
 |  | 
 |     if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 || | 
 |      memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0) | 
 |       continue; | 
 |  | 
 |     found = TRUE; | 
 |     addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen); | 
 |     if (addrLen > *len) { | 
 |       ret = ERROR_INSUFFICIENT_BUFFER; | 
 |       *len = addrLen; | 
 |     } | 
 |     else { | 
 |       if (addrLen > 0) | 
 |         memcpy(addr, LLADDR(sdl), addrLen); | 
 |       /* zero out remaining bytes for broken implementations */ | 
 |       memset(addr + addrLen, 0, *len - addrLen); | 
 |       *len = addrLen; | 
 | #if defined(HAVE_NET_IF_TYPES_H) | 
 |       switch (sdl->sdl_type) | 
 |       { | 
 |         case IFT_ETHER: | 
 |           *type = MIB_IF_TYPE_ETHERNET; | 
 |           break; | 
 |         case IFT_FDDI: | 
 |           *type = MIB_IF_TYPE_FDDI; | 
 |           break; | 
 |         case IFT_ISO88024: /* Token Bus */ | 
 |           *type = MIB_IF_TYPE_TOKENRING; | 
 |           break; | 
 |         case IFT_ISO88025: /* Token Ring */ | 
 |           *type = MIB_IF_TYPE_TOKENRING; | 
 |           break; | 
 |         case IFT_PPP: | 
 |           *type = MIB_IF_TYPE_PPP; | 
 |           break; | 
 |         case IFT_SLIP: | 
 |           *type = MIB_IF_TYPE_SLIP; | 
 |           break; | 
 |         case IFT_LOOP: | 
 |           *type = MIB_IF_TYPE_LOOPBACK; | 
 |           break; | 
 |         default: | 
 |           *type = MIB_IF_TYPE_OTHER; | 
 |       } | 
 | #else | 
 |       /* default if we don't know */ | 
 |       *type = MIB_IF_TYPE_ETHERNET; | 
 | #endif | 
 |       ret = NO_ERROR; | 
 |     } | 
 |   } | 
 |   HeapFree(GetProcessHeap(), 0, buf); | 
 |   return ret; | 
 | } | 
 | #endif | 
 |  | 
 | DWORD getInterfacePhysicalByIndex(IF_INDEX index, PDWORD len, PBYTE addr, | 
 |  PDWORD type) | 
 | { | 
 |   char nameBuf[IF_NAMESIZE]; | 
 |   char *name = getInterfaceNameByIndex(index, nameBuf); | 
 |  | 
 |   if (name) | 
 |     return getInterfacePhysicalByName(name, len, addr, type); | 
 |   else | 
 |     return ERROR_INVALID_DATA; | 
 | } | 
 |  | 
 | DWORD getInterfaceMtuByName(const char *name, PDWORD mtu) | 
 | { | 
 |   DWORD ret; | 
 |   int fd; | 
 |  | 
 |   if (!name) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |   if (!mtu) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |  | 
 |   fd = socket(PF_INET, SOCK_DGRAM, 0); | 
 |   if (fd != -1) { | 
 |     struct ifreq ifr; | 
 |  | 
 |     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); | 
 |     if ((ioctl(fd, SIOCGIFMTU, &ifr))) | 
 |       ret = ERROR_INVALID_DATA; | 
 |     else { | 
 | #ifndef __sun | 
 |       *mtu = ifr.ifr_mtu; | 
 | #else | 
 |       *mtu = ifr.ifr_metric; | 
 | #endif | 
 |       ret = NO_ERROR; | 
 |     } | 
 |     close(fd); | 
 |   } | 
 |   else | 
 |     ret = ERROR_NO_MORE_FILES; | 
 |   return ret; | 
 | } | 
 |  | 
 | DWORD getInterfaceStatusByName(const char *name, INTERNAL_IF_OPER_STATUS *status) | 
 | { | 
 |   DWORD ret; | 
 |   int fd; | 
 |  | 
 |   if (!name) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |   if (!status) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |  | 
 |   fd = socket(PF_INET, SOCK_DGRAM, 0); | 
 |   if (fd != -1) { | 
 |     struct ifreq ifr; | 
 |  | 
 |     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ); | 
 |     if ((ioctl(fd, SIOCGIFFLAGS, &ifr))) | 
 |       ret = ERROR_INVALID_DATA; | 
 |     else { | 
 |       if (ifr.ifr_flags & IFF_UP) | 
 |         *status = MIB_IF_OPER_STATUS_OPERATIONAL; | 
 |       else | 
 |         *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL; | 
 |       ret = NO_ERROR; | 
 |     } | 
 |     close(fd); | 
 |   } | 
 |   else | 
 |     ret = ERROR_NO_MORE_FILES; | 
 |   return ret; | 
 | } | 
 |  | 
 | DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry) | 
 | { | 
 |   BYTE addr[MAX_INTERFACE_PHYSADDR]; | 
 |   DWORD ret, len = sizeof(addr), type; | 
 |  | 
 |   if (!name) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |   if (!entry) | 
 |     return ERROR_INVALID_PARAMETER; | 
 |  | 
 |   if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) { | 
 |     WCHAR *assigner; | 
 |     const char *walker; | 
 |  | 
 |     memset(entry, 0, sizeof(MIB_IFROW)); | 
 |     for (assigner = entry->wszName, walker = name; *walker;  | 
 |      walker++, assigner++) | 
 |       *assigner = *walker; | 
 |     *assigner = 0; | 
 |     getInterfaceIndexByName(name, &entry->dwIndex); | 
 |     entry->dwPhysAddrLen = len; | 
 |     memcpy(entry->bPhysAddr, addr, len); | 
 |     memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len); | 
 |     entry->dwType = type; | 
 |     /* FIXME: how to calculate real speed? */ | 
 |     getInterfaceMtuByName(name, &entry->dwMtu); | 
 |     /* lie, there's no "administratively down" here */ | 
 |     entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP; | 
 |     getInterfaceStatusByName(name, &entry->dwOperStatus); | 
 |     /* punt on dwLastChange? */ | 
 |     entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1); | 
 |     memcpy(entry->bDescr, name, entry->dwDescrLen); | 
 |     entry->bDescr[entry->dwDescrLen] = '\0'; | 
 |     entry->dwDescrLen++; | 
 |     ret = NO_ERROR; | 
 |   } | 
 |   else | 
 |     ret = ERROR_INVALID_DATA; | 
 |   return ret; | 
 | } | 
 |  | 
 | static DWORD getIPAddrRowByName(PMIB_IPADDRROW ipAddrRow, const char *ifName, | 
 |  const struct sockaddr *sa) | 
 | { | 
 |   DWORD ret, bcast; | 
 |  | 
 |   ret = getInterfaceIndexByName(ifName, &ipAddrRow->dwIndex); | 
 |   memcpy(&ipAddrRow->dwAddr, sa->sa_data + 2, sizeof(DWORD)); | 
 |   ipAddrRow->dwMask = getInterfaceMaskByName(ifName); | 
 |   /* the dwBCastAddr member isn't the broadcast address, it indicates whether | 
 |    * the interface uses the 1's broadcast address (1) or the 0's broadcast | 
 |    * address (0). | 
 |    */ | 
 |   bcast = getInterfaceBCastAddrByName(ifName); | 
 |   ipAddrRow->dwBCastAddr = (bcast & ipAddrRow->dwMask) ? 1 : 0; | 
 |   /* FIXME: hardcoded reasm size, not sure where to get it */ | 
 |   ipAddrRow->dwReasmSize = 65535; | 
 |   ipAddrRow->unused1 = 0; | 
 |   ipAddrRow->wType = 0; | 
 |   return ret; | 
 | } | 
 |  | 
 | #ifdef HAVE_IFADDRS_H | 
 |  | 
 | /* Counts the IPv4 addresses in the system using the return value from | 
 |  * getifaddrs, returning the count. | 
 |  */ | 
 | static DWORD countIPv4Addresses(struct ifaddrs *ifa) | 
 | { | 
 |   DWORD numAddresses = 0; | 
 |  | 
 |   for (; ifa; ifa = ifa->ifa_next) | 
 |     if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) | 
 |       numAddresses++; | 
 |   return numAddresses; | 
 | } | 
 |  | 
 | DWORD getNumIPAddresses(void) | 
 | { | 
 |   DWORD numAddresses = 0; | 
 |   struct ifaddrs *ifa; | 
 |  | 
 |   if (!getifaddrs(&ifa)) | 
 |   { | 
 |     numAddresses = countIPv4Addresses(ifa); | 
 |     freeifaddrs(ifa); | 
 |   } | 
 |   return numAddresses; | 
 | } | 
 |  | 
 | DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags) | 
 | { | 
 |   DWORD ret; | 
 |  | 
 |   if (!ppIpAddrTable) | 
 |     ret = ERROR_INVALID_PARAMETER; | 
 |   else | 
 |   { | 
 |     struct ifaddrs *ifa; | 
 |  | 
 |     if (!getifaddrs(&ifa)) | 
 |     { | 
 |       DWORD size = sizeof(MIB_IPADDRTABLE); | 
 |       DWORD numAddresses = countIPv4Addresses(ifa); | 
 |  | 
 |       if (numAddresses > 1) | 
 |         size += (numAddresses - 1) * sizeof(MIB_IPADDRROW); | 
 |       *ppIpAddrTable = HeapAlloc(heap, flags, size); | 
 |       if (*ppIpAddrTable) | 
 |       { | 
 |         DWORD i = 0; | 
 |         struct ifaddrs *ifp; | 
 |  | 
 |         ret = NO_ERROR; | 
 |         (*ppIpAddrTable)->dwNumEntries = numAddresses; | 
 |         for (ifp = ifa; !ret && ifp; ifp = ifp->ifa_next) | 
 |         { | 
 |           if (!ifp->ifa_addr || ifp->ifa_addr->sa_family != AF_INET) | 
 |             continue; | 
 |  | 
 |           ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifp->ifa_name, | 
 |            ifp->ifa_addr); | 
 |           i++; | 
 |         } | 
 |       } | 
 |       else | 
 |         ret = ERROR_OUTOFMEMORY; | 
 |       freeifaddrs(ifa); | 
 |     } | 
 |     else | 
 |       ret = ERROR_INVALID_PARAMETER; | 
 |   } | 
 |   return ret; | 
 | } | 
 |  | 
 | ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs) | 
 | { | 
 |   struct ifaddrs *ifa; | 
 |   ULONG ret; | 
 |  | 
 |   if (!getifaddrs(&ifa)) | 
 |   { | 
 |     struct ifaddrs *p; | 
 |     ULONG n; | 
 |     char name[IFNAMSIZ]; | 
 |  | 
 |     getInterfaceNameByIndex(index, name); | 
 |     for (p = ifa, n = 0; p; p = p->ifa_next) | 
 |       if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 && | 
 |           !strcmp(name, p->ifa_name)) | 
 |         n++; | 
 |     if (n) | 
 |     { | 
 |       *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) + | 
 |                          sizeof(struct WS_sockaddr_in6))); | 
 |       if (*addrs) | 
 |       { | 
 |         struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)( | 
 |             (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS)); | 
 |  | 
 |         for (p = ifa, n = 0; p; p = p->ifa_next) | 
 |         { | 
 |           if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 && | 
 |               !strcmp(name, p->ifa_name)) | 
 |           { | 
 |             struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr; | 
 |  | 
 |             next_addr->sin6_family = WS_AF_INET6; | 
 |             next_addr->sin6_port = addr->sin6_port; | 
 |             next_addr->sin6_flowinfo = addr->sin6_flowinfo; | 
 |             memcpy(&next_addr->sin6_addr, &addr->sin6_addr, | 
 |              sizeof(next_addr->sin6_addr)); | 
 |             next_addr->sin6_scope_id = addr->sin6_scope_id; | 
 |             (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr; | 
 |             (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6); | 
 |             next_addr++; | 
 |             n++; | 
 |           } | 
 |         } | 
 |         *num_addrs = n; | 
 |         ret = ERROR_SUCCESS; | 
 |       } | 
 |       else | 
 |         ret = ERROR_OUTOFMEMORY; | 
 |     } | 
 |     else | 
 |     { | 
 |       *addrs = NULL; | 
 |       *num_addrs = 0; | 
 |       ret = ERROR_SUCCESS; | 
 |     } | 
 |     freeifaddrs(ifa); | 
 |   } | 
 |   else | 
 |     ret = ERROR_NO_DATA; | 
 |   return ret; | 
 | } | 
 |  | 
 | #else | 
 |  | 
 | /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning | 
 |  * the count to you in *pcAddresses.  It also returns to you the struct ifconf | 
 |  * used by the call to ioctl, so that you may process the addresses further. | 
 |  * Free ifc->ifc_buf using HeapFree. | 
 |  * Returns NO_ERROR on success, something else on failure. | 
 |  */ | 
 | static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc) | 
 | { | 
 |   DWORD ret; | 
 |   int fd; | 
 |  | 
 |   fd = socket(PF_INET, SOCK_DGRAM, 0); | 
 |   if (fd != -1) { | 
 |     int ioctlRet = 0; | 
 |     DWORD guessedNumAddresses = 0, numAddresses = 0; | 
 |     caddr_t ifPtr; | 
 |     int lastlen; | 
 |  | 
 |     ret = NO_ERROR; | 
 |     ifc->ifc_len = 0; | 
 |     ifc->ifc_buf = NULL; | 
 |     /* there is no way to know the interface count beforehand, | 
 |        so we need to loop again and again upping our max each time | 
 |        until returned is constant across 2 calls */ | 
 |     do { | 
 |       lastlen = ifc->ifc_len; | 
 |       HeapFree(GetProcessHeap(), 0, ifc->ifc_buf); | 
 |       if (guessedNumAddresses == 0) | 
 |         guessedNumAddresses = INITIAL_INTERFACES_ASSUMED; | 
 |       else | 
 |         guessedNumAddresses *= 2; | 
 |       ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses; | 
 |       ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len); | 
 |       ioctlRet = ioctl(fd, SIOCGIFCONF, ifc); | 
 |     } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen)); | 
 |  | 
 |     if (ioctlRet == 0) { | 
 |       ifPtr = ifc->ifc_buf; | 
 |       while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) { | 
 |         struct ifreq *ifr = (struct ifreq *)ifPtr; | 
 |  | 
 |         if (ifr->ifr_addr.sa_family == AF_INET) | 
 |           numAddresses++; | 
 |  | 
 |         ifPtr += ifreq_len((struct ifreq *)ifPtr); | 
 |       } | 
 |     } | 
 |     else | 
 |       ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */ | 
 |     if (!ret) | 
 |       *pcAddresses = numAddresses; | 
 |     else | 
 |     { | 
 |       HeapFree(GetProcessHeap(), 0, ifc->ifc_buf); | 
 |       ifc->ifc_buf = NULL; | 
 |     } | 
 |     close(fd); | 
 |   } | 
 |   else | 
 |     ret = ERROR_NO_SYSTEM_RESOURCES; | 
 |   return ret; | 
 | } | 
 |  | 
 | DWORD getNumIPAddresses(void) | 
 | { | 
 |   DWORD numAddresses = 0; | 
 |   struct ifconf ifc; | 
 |  | 
 |   if (!enumIPAddresses(&numAddresses, &ifc)) | 
 |     HeapFree(GetProcessHeap(), 0, ifc.ifc_buf); | 
 |   return numAddresses; | 
 | } | 
 |  | 
 | DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags) | 
 | { | 
 |   DWORD ret; | 
 |  | 
 |   if (!ppIpAddrTable) | 
 |     ret = ERROR_INVALID_PARAMETER; | 
 |   else | 
 |   { | 
 |     DWORD numAddresses = 0; | 
 |     struct ifconf ifc; | 
 |  | 
 |     ret = enumIPAddresses(&numAddresses, &ifc); | 
 |     if (!ret) | 
 |     { | 
 |       DWORD size = sizeof(MIB_IPADDRTABLE); | 
 |  | 
 |       if (numAddresses > 1) | 
 |         size += (numAddresses - 1) * sizeof(MIB_IPADDRROW); | 
 |       *ppIpAddrTable = HeapAlloc(heap, flags, size); | 
 |       if (*ppIpAddrTable) { | 
 |         DWORD i = 0; | 
 |         caddr_t ifPtr; | 
 |  | 
 |         ret = NO_ERROR; | 
 |         (*ppIpAddrTable)->dwNumEntries = numAddresses; | 
 |         ifPtr = ifc.ifc_buf; | 
 |         while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) { | 
 |           struct ifreq *ifr = (struct ifreq *)ifPtr; | 
 |  | 
 |           ifPtr += ifreq_len(ifr); | 
 |  | 
 |           if (ifr->ifr_addr.sa_family != AF_INET) | 
 |              continue; | 
 |  | 
 |           ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifr->ifr_name, | 
 |            &ifr->ifr_addr); | 
 |           i++; | 
 |         } | 
 |       } | 
 |       else | 
 |         ret = ERROR_OUTOFMEMORY; | 
 |       HeapFree(GetProcessHeap(), 0, ifc.ifc_buf); | 
 |     } | 
 |   } | 
 |   return ret; | 
 | } | 
 |  | 
 | ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs) | 
 | { | 
 |   *addrs = NULL; | 
 |   *num_addrs = 0; | 
 |   return ERROR_SUCCESS; | 
 | } | 
 |  | 
 | #endif | 
 |  | 
 | char *toIPAddressString(unsigned int addr, char string[16]) | 
 | { | 
 |   if (string) { | 
 |     struct in_addr iAddr; | 
 |  | 
 |     iAddr.s_addr = addr; | 
 |     /* extra-anal, just to make auditors happy */ | 
 |     lstrcpynA(string, inet_ntoa(iAddr), 16); | 
 |   } | 
 |   return string; | 
 | } |