1 /* Copyright (C) 2003 Juan Lang
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * Implementation notes
18 * Interface index fun:
19 * - Windows may rely on an index being cleared in the topmost 8 bits in some
20 * APIs; see GetFriendlyIfIndex and the mention of "backward compatible"
21 * indexes. It isn't clear which APIs might fail with non-backward-compatible
22 * indexes, but I'll keep them bits clear just in case.
23 * - Even though if_nametoindex and if_indextoname seem to be pretty portable,
24 * Linux, at any rate, uses the same interface index for all virtual
25 * interfaces of a real interface as well as for the real interface itself.
26 * If I used the Linux index as my index, this would break my statement that
27 * an index is a key, and that an interface has 0 or 1 IP addresses.
28 * If that behavior were consistent across UNIXen (I don't know), it could
29 * help me implement multiple IP addresses more in the Windows way.
30 * I used to assert I could not use UNIX interface indexes as my iphlpapi
31 * indexes due to restrictions in netapi32 and wsock32, but I have removed
32 * those restrictions, so using if_nametoindex and if_indextoname rather
33 * than my current mess would probably be better.
35 * - I don't support IPv6 addresses here, since SIOCGIFCONF can't return them
37 * There are three implemened methods for determining the MAC address of an
39 * - a specific IOCTL (Linux)
40 * - looking in the ARP cache (at least Solaris)
41 * - using the sysctl interface (FreeBSD and MacOSX)
42 * Solaris and some others have SIOCGENADDR, but I haven't gotten that to work
43 * on the Solaris boxes at SourceForge's compile farm, whereas SIOCGARP does.
57 #include <sys/types.h>
59 #ifdef HAVE_SYS_SOCKET_H
60 #include <sys/socket.h>
63 #ifdef HAVE_NETINET_IN_H
64 #include <netinet/in.h>
67 #ifdef HAVE_ARPA_INET_H
68 #include <arpa/inet.h>
75 #ifdef HAVE_NET_IF_ARP_H
76 #include <net/if_arp.h>
79 #ifdef HAVE_NET_ROUTE_H
80 #include <net/route.h>
83 #ifdef HAVE_SYS_IOCTL_H
84 #include <sys/ioctl.h>
87 #ifdef HAVE_SYS_SYSCTL_H
88 #include <sys/sysctl.h>
91 #ifdef HAVE_SYS_SOCKIO_H
92 #include <sys/sockio.h>
95 #ifdef HAVE_NET_IF_DL_H
96 #include <net/if_dl.h>
99 #ifdef HAVE_NET_IF_TYPES_H
100 #include <net/if_types.h>
105 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
106 #define ifreq_len(ifr) \
107 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
109 #define ifreq_len(ifr) sizeof(struct ifreq)
117 #define INADDR_NONE (~0U)
120 #define INITIAL_INTERFACES_ASSUMED 4
122 #define INDEX_IS_LOOPBACK 0x00800000
124 /* Type declarations */
126 typedef struct _InterfaceNameMapEntry {
130 } InterfaceNameMapEntry;
132 typedef struct _InterfaceNameMap {
136 InterfaceNameMapEntry table[1];
139 /* Global variables */
141 static CRITICAL_SECTION mapCS;
142 static InterfaceNameMap *gNonLoopbackInterfaceMap = NULL;
143 static InterfaceNameMap *gLoopbackInterfaceMap = NULL;
147 void interfaceMapInit(void)
149 InitializeCriticalSection(&mapCS);
152 void interfaceMapFree(void)
154 DeleteCriticalSection(&mapCS);
155 HeapFree(GetProcessHeap(), 0, gNonLoopbackInterfaceMap);
156 HeapFree(GetProcessHeap(), 0, gLoopbackInterfaceMap);
159 /* Sizes the passed-in map to have enough space for numInterfaces interfaces.
160 * If map is NULL, allocates a new map. If it is not, may reallocate the
161 * existing map and return a map of increased size. Returns the allocated map,
162 * or NULL if it could not allocate a map of the requested size.
164 static InterfaceNameMap *sizeMap(InterfaceNameMap *map, DWORD numInterfaces)
167 numInterfaces = max(numInterfaces, INITIAL_INTERFACES_ASSUMED);
168 map = (InterfaceNameMap *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
169 sizeof(InterfaceNameMap) +
170 (numInterfaces - 1) * sizeof(InterfaceNameMapEntry));
172 map->numAllocated = numInterfaces;
175 if (map->numAllocated < numInterfaces) {
176 map = (InterfaceNameMap *)HeapReAlloc(GetProcessHeap(), 0, map,
177 sizeof(InterfaceNameMap) +
178 (numInterfaces - 1) * sizeof(InterfaceNameMapEntry));
180 memset(&map->table[map->numAllocated], 0,
181 (numInterfaces - map->numAllocated) * sizeof(InterfaceNameMapEntry));
187 static int isLoopbackInterface(int fd, const char *name)
194 strncpy(ifr.ifr_name, name, IFNAMSIZ);
195 ifr.ifr_name[IFNAMSIZ-1] = '\0';
196 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
197 ret = ifr.ifr_flags & IFF_LOOPBACK;
202 static void countInterfaces(int fd, caddr_t buf, size_t len)
205 DWORD numNonLoopbackInterfaces = 0, numLoopbackInterfaces = 0;
207 while (ifPtr && ifPtr < buf + len) {
208 struct ifreq *ifr = (struct ifreq *)ifPtr;
210 if (isLoopbackInterface(fd, ifr->ifr_name))
211 numLoopbackInterfaces++;
213 numNonLoopbackInterfaces++;
214 ifPtr += ifreq_len(ifr);
216 gNonLoopbackInterfaceMap = sizeMap(gNonLoopbackInterfaceMap,
217 numNonLoopbackInterfaces);
218 gLoopbackInterfaceMap = sizeMap(gLoopbackInterfaceMap,
219 numLoopbackInterfaces);
222 /* Stores the name in the given map, and increments the map's numInterfaces
223 * member if stored successfully. Will store in the same slot as previously if
224 * usedLastPass is set, otherwise will store in a new slot.
225 * Assumes map and name are not NULL, and the usedLastPass flag is set
226 * correctly for each entry in the map, and that map->numInterfaces <
228 * FIXME: this is kind of expensive, doing a linear scan of the map with a
229 * string comparison of each entry to find the old slot.
231 static void storeInterfaceInMap(InterfaceNameMap *map, const char *name)
237 /* look for previous slot, mark in use if so */
238 for (ndx = 0; !stored && ndx < map->nextAvailable; ndx++) {
239 if (map->table[ndx].usedLastPass && !strncmp(map->table[ndx].name, name,
240 sizeof(map->table[ndx].name))) {
241 map->table[ndx].inUse = TRUE;
245 /* look for new slot */
246 for (ndx = 0; !stored && ndx < map->numAllocated; ndx++) {
247 if (!map->table[ndx].inUse) {
248 strncpy(map->table[ndx].name, name, IFNAMSIZ);
249 map->table[ndx].name[IFNAMSIZ-1] = '\0';
250 map->table[ndx].inUse = TRUE;
252 if (ndx >= map->nextAvailable)
253 map->nextAvailable = ndx + 1;
257 map->numInterfaces++;
261 /* Sets all used entries' usedLastPass flag to their inUse flag, clears
262 * their inUse flag, and clears their numInterfaces member.
264 static void markOldInterfaces(InterfaceNameMap *map)
269 map->numInterfaces = 0;
270 for (ndx = 0; ndx < map->nextAvailable; ndx++) {
271 map->table[ndx].usedLastPass = map->table[ndx].inUse;
272 map->table[ndx].inUse = FALSE;
277 static void classifyInterfaces(int fd, caddr_t buf, size_t len)
281 markOldInterfaces(gNonLoopbackInterfaceMap);
282 markOldInterfaces(gLoopbackInterfaceMap);
283 while (ifPtr && ifPtr < buf + len) {
284 struct ifreq *ifr = (struct ifreq *)ifPtr;
286 if (ifr->ifr_addr.sa_family == AF_INET) {
287 if (isLoopbackInterface(fd, ifr->ifr_name))
288 storeInterfaceInMap(gLoopbackInterfaceMap, ifr->ifr_name);
290 storeInterfaceInMap(gNonLoopbackInterfaceMap, ifr->ifr_name);
292 ifPtr += ifreq_len(ifr);
296 static void enumerateInterfaces(void)
300 fd = socket(PF_INET, SOCK_DGRAM, 0);
302 int ret, guessedNumInterfaces;
305 /* try to avoid silly heap action by starting with the right size buffer */
306 guessedNumInterfaces = 0;
307 if (gNonLoopbackInterfaceMap)
308 guessedNumInterfaces += gNonLoopbackInterfaceMap->numInterfaces;
309 if (gLoopbackInterfaceMap)
310 guessedNumInterfaces += gLoopbackInterfaceMap->numInterfaces;
313 memset(&ifc, 0, sizeof(ifc));
314 /* there is no way to know the interface count beforehand,
315 so we need to loop again and again upping our max each time
316 until returned < max */
318 if (guessedNumInterfaces == 0)
319 guessedNumInterfaces = INITIAL_INTERFACES_ASSUMED;
321 guessedNumInterfaces *= 2;
322 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
323 ifc.ifc_len = sizeof(struct ifreq) * guessedNumInterfaces;
324 ifc.ifc_buf = (char *)HeapAlloc(GetProcessHeap(), 0, ifc.ifc_len);
325 ret = ioctl(fd, SIOCGIFCONF, &ifc);
327 ifc.ifc_len == (sizeof(struct ifreq) * guessedNumInterfaces));
330 EnterCriticalSection(&mapCS);
331 countInterfaces(fd, ifc.ifc_buf, ifc.ifc_len);
332 classifyInterfaces(fd, ifc.ifc_buf, ifc.ifc_len);
333 LeaveCriticalSection(&mapCS);
336 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
341 DWORD getNumNonLoopbackInterfaces(void)
343 enumerateInterfaces();
344 return gNonLoopbackInterfaceMap ? gNonLoopbackInterfaceMap->numInterfaces : 0;
347 DWORD getNumInterfaces(void)
349 DWORD ret = getNumNonLoopbackInterfaces();
351 ret += gLoopbackInterfaceMap ? gLoopbackInterfaceMap->numInterfaces : 0;
355 const char *getInterfaceNameByIndex(DWORD index)
358 InterfaceNameMap *map;
359 const char *ret = NULL;
361 EnterCriticalSection(&mapCS);
362 if (index & INDEX_IS_LOOPBACK) {
363 realIndex = index ^ INDEX_IS_LOOPBACK;
364 map = gLoopbackInterfaceMap;
368 map = gNonLoopbackInterfaceMap;
370 if (map && realIndex < map->nextAvailable)
371 ret = map->table[realIndex].name;
372 LeaveCriticalSection(&mapCS);
376 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
382 return ERROR_INVALID_PARAMETER;
384 return ERROR_INVALID_PARAMETER;
386 EnterCriticalSection(&mapCS);
387 for (ndx = 0; !found && gNonLoopbackInterfaceMap &&
388 ndx < gNonLoopbackInterfaceMap->nextAvailable; ndx++)
389 if (!strncmp(gNonLoopbackInterfaceMap->table[ndx].name, name, IFNAMSIZ)) {
393 for (ndx = 0; !found && gLoopbackInterfaceMap &&
394 ndx < gLoopbackInterfaceMap->nextAvailable; ndx++)
395 if (!strncmp(gLoopbackInterfaceMap->table[ndx].name, name, IFNAMSIZ)) {
397 *index = ndx | INDEX_IS_LOOPBACK;
399 LeaveCriticalSection(&mapCS);
403 ret = ERROR_INVALID_DATA;
407 static void addMapEntriesToIndexTable(InterfaceIndexTable *table,
408 const InterfaceNameMap *map)
413 for (ndx = 0; ndx < map->nextAvailable &&
414 table->numIndexes < table->numAllocated; ndx++)
415 if (map->table[ndx].inUse) {
416 DWORD externalNdx = ndx;
418 if (map == gLoopbackInterfaceMap)
419 externalNdx |= INDEX_IS_LOOPBACK;
420 table->indexes[table->numIndexes++] = externalNdx;
425 InterfaceIndexTable *getInterfaceIndexTable(void)
428 InterfaceIndexTable *ret;
430 EnterCriticalSection(&mapCS);
431 numInterfaces = getNumInterfaces();
432 ret = (InterfaceIndexTable *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
433 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
435 ret->numAllocated = numInterfaces;
436 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
437 addMapEntriesToIndexTable(ret, gLoopbackInterfaceMap);
439 LeaveCriticalSection(&mapCS);
443 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
446 InterfaceIndexTable *ret;
448 EnterCriticalSection(&mapCS);
449 numInterfaces = getNumNonLoopbackInterfaces();
450 ret = (InterfaceIndexTable *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
451 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
453 ret->numAllocated = numInterfaces;
454 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
456 LeaveCriticalSection(&mapCS);
460 DWORD getInterfaceIPAddrByName(const char *name)
462 DWORD ret = INADDR_ANY;
465 int fd = socket(PF_INET, SOCK_DGRAM, 0);
470 strncpy(ifr.ifr_name, name, IFNAMSIZ);
471 ifr.ifr_name[IFNAMSIZ-1] = '\0';
472 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0)
473 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
480 DWORD getInterfaceIPAddrByIndex(DWORD index)
483 const char *name = getInterfaceNameByIndex(index);
486 ret = getInterfaceIPAddrByName(name);
492 DWORD getInterfaceBCastAddrByName(const char *name)
494 DWORD ret = INADDR_ANY;
497 int fd = socket(PF_INET, SOCK_DGRAM, 0);
502 strncpy(ifr.ifr_name, name, IFNAMSIZ);
503 ifr.ifr_name[IFNAMSIZ-1] = '\0';
504 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
505 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
512 DWORD getInterfaceBCastAddrByIndex(DWORD index)
515 const char *name = getInterfaceNameByIndex(index);
518 ret = getInterfaceBCastAddrByName(name);
524 DWORD getInterfaceMaskByName(const char *name)
526 DWORD ret = INADDR_NONE;
529 int fd = socket(PF_INET, SOCK_DGRAM, 0);
534 strncpy(ifr.ifr_name, name, IFNAMSIZ);
535 ifr.ifr_name[IFNAMSIZ-1] = '\0';
536 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
537 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
544 DWORD getInterfaceMaskByIndex(DWORD index)
547 const char *name = getInterfaceNameByIndex(index);
550 ret = getInterfaceMaskByName(name);
556 #if defined (SIOCGIFHWADDR)
557 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
563 if (!name || !len || !addr || !type)
564 return ERROR_INVALID_PARAMETER;
566 fd = socket(PF_INET, SOCK_DGRAM, 0);
570 memset(&ifr, 0, sizeof(struct ifreq));
571 strncpy(ifr.ifr_name, name, IFNAMSIZ);
572 ifr.ifr_name[IFNAMSIZ-1] = '\0';
573 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
574 ret = ERROR_INVALID_DATA;
576 unsigned int addrLen;
578 switch (ifr.ifr_hwaddr.sa_family)
580 #ifdef ARPHRD_LOOPBACK
581 case ARPHRD_LOOPBACK:
583 *type = MIB_IF_TYPE_LOOPBACK;
589 *type = MIB_IF_TYPE_ETHERNET;
595 *type = MIB_IF_TYPE_FDDI;
598 #ifdef ARPHRD_IEEE802
599 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
601 *type = MIB_IF_TYPE_TOKENRING;
604 #ifdef ARPHRD_IEEE802_TR
605 case ARPHRD_IEEE802_TR: /* also Token Ring? */
607 *type = MIB_IF_TYPE_TOKENRING;
613 *type = MIB_IF_TYPE_SLIP;
619 *type = MIB_IF_TYPE_PPP;
623 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
624 *type = MIB_IF_TYPE_OTHER;
626 if (addrLen > *len) {
627 ret = ERROR_INSUFFICIENT_BUFFER;
632 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
633 /* zero out remaining bytes for broken implementations */
634 memset(addr + addrLen, 0, *len - addrLen);
642 ret = ERROR_NO_MORE_FILES;
645 #elif defined (SIOCGARP)
646 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
652 if (!name || !len || !addr || !type)
653 return ERROR_INVALID_PARAMETER;
655 fd = socket(PF_INET, SOCK_DGRAM, 0);
657 if (isLoopbackInterface(fd, name)) {
658 *type = MIB_IF_TYPE_LOOPBACK;
659 memset(addr, 0, *len);
665 struct sockaddr_in *saddr;
667 memset(&arp, 0, sizeof(struct arpreq));
668 arp.arp_pa.sa_family = AF_INET;
669 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
670 saddr->sin_family = AF_INET;
671 saddr->sin_addr.s_addr = getInterfaceIPAddrByName(name);
672 if ((ioctl(fd, SIOCGARP, &arp)))
673 ret = ERROR_INVALID_DATA;
675 /* FIXME: heh: who said it was ethernet? */
676 int addrLen = ETH_ALEN;
678 if (addrLen > *len) {
679 ret = ERROR_INSUFFICIENT_BUFFER;
684 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
685 /* zero out remaining bytes for broken implementations */
686 memset(addr + addrLen, 0, *len - addrLen);
688 *type = MIB_IF_TYPE_ETHERNET;
696 ret = ERROR_NO_MORE_FILES;
700 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
701 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
705 struct if_msghdr *ifm;
706 struct sockaddr_dl *sdl;
709 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
713 if (!name || !len || !addr || !type)
714 return ERROR_INVALID_PARAMETER;
716 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
717 return ERROR_NO_MORE_FILES;
719 buf = (u_char *)HeapAlloc(GetProcessHeap(), 0, mibLen);
721 return ERROR_NOT_ENOUGH_MEMORY;
723 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
724 HeapFree(GetProcessHeap(), 0, buf);
725 return ERROR_NO_MORE_FILES;
728 ret = ERROR_INVALID_DATA;
729 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
730 ifm = (struct if_msghdr *)p;
731 sdl = (struct sockaddr_dl *)(ifm + 1);
733 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
736 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
737 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
741 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
742 if (addrLen > *len) {
743 ret = ERROR_INSUFFICIENT_BUFFER;
748 memcpy(addr, LLADDR(sdl), addrLen);
749 /* zero out remaining bytes for broken implementations */
750 memset(addr + addrLen, 0, *len - addrLen);
752 #if defined(HAVE_NET_IF_TYPES_H)
753 switch (sdl->sdl_type)
756 *type = MIB_IF_TYPE_ETHERNET;
759 *type = MIB_IF_TYPE_FDDI;
761 case IFT_ISO88024: /* Token Bus */
762 *type = MIB_IF_TYPE_TOKENRING;
764 case IFT_ISO88025: /* Token Ring */
765 *type = MIB_IF_TYPE_TOKENRING;
768 *type = MIB_IF_TYPE_PPP;
771 *type = MIB_IF_TYPE_SLIP;
774 *type = MIB_IF_TYPE_LOOPBACK;
777 *type = MIB_IF_TYPE_OTHER;
780 /* default if we don't know */
781 *type = MIB_IF_TYPE_ETHERNET;
786 HeapFree(GetProcessHeap(), 0, buf);
791 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
794 const char *name = getInterfaceNameByIndex(index);
797 return getInterfacePhysicalByName(name, len, addr, type);
799 return ERROR_INVALID_DATA;
802 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
808 return ERROR_INVALID_PARAMETER;
810 return ERROR_INVALID_PARAMETER;
812 fd = socket(PF_INET, SOCK_DGRAM, 0);
816 strncpy(ifr.ifr_name, name, IFNAMSIZ);
817 ifr.ifr_name[IFNAMSIZ-1] = '\0';
818 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
819 ret = ERROR_INVALID_DATA;
824 *mtu = ifr.ifr_metric;
830 ret = ERROR_NO_MORE_FILES;
834 DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu)
836 const char *name = getInterfaceNameByIndex(index);
839 return getInterfaceMtuByName(name, mtu);
841 return ERROR_INVALID_DATA;
844 DWORD getInterfaceStatusByName(const char *name, PDWORD status)
850 return ERROR_INVALID_PARAMETER;
852 return ERROR_INVALID_PARAMETER;
854 fd = socket(PF_INET, SOCK_DGRAM, 0);
858 strncpy(ifr.ifr_name, name, IFNAMSIZ);
859 ifr.ifr_name[IFNAMSIZ-1] = '\0';
860 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
861 ret = ERROR_INVALID_DATA;
863 if (ifr.ifr_flags & IFF_UP)
864 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
866 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
871 ret = ERROR_NO_MORE_FILES;
875 DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status)
877 const char *name = getInterfaceNameByIndex(index);
880 return getInterfaceStatusByName(name, status);
882 return ERROR_INVALID_DATA;
885 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
887 BYTE addr[MAX_INTERFACE_PHYSADDR];
888 DWORD ret, len = sizeof(addr), type;
891 return ERROR_INVALID_PARAMETER;
893 return ERROR_INVALID_PARAMETER;
895 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
899 memset(entry, 0, sizeof(MIB_IFROW));
900 for (assigner = entry->wszName, walker = name; *walker;
901 walker++, assigner++)
904 getInterfaceIndexByName(name, &entry->dwIndex);
905 entry->dwPhysAddrLen = len;
906 memcpy(entry->bPhysAddr, addr, len);
907 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
908 entry->dwType = type;
909 /* FIXME: how to calculate real speed? */
910 getInterfaceMtuByName(name, &entry->dwMtu);
911 /* lie, there's no "administratively down" here */
912 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
913 getInterfaceStatusByName(name, &entry->dwOperStatus);
914 /* punt on dwLastChange? */
915 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
916 memcpy(entry->bDescr, name, entry->dwDescrLen);
917 entry->bDescr[entry->dwDescrLen] = '\0';
922 ret = ERROR_INVALID_DATA;
926 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
928 const char *name = getInterfaceNameByIndex(index);
931 return getInterfaceEntryByName(name, entry);
933 return ERROR_INVALID_DATA;
936 char *toIPAddressString(unsigned int addr, char string[16])
939 struct in_addr iAddr;
942 /* extra-anal, just to make auditors happy */
943 strncpy(string, inet_ntoa(iAddr), 16);