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 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
169 sizeof(InterfaceNameMap) +
170 (numInterfaces - 1) * sizeof(InterfaceNameMapEntry));
172 map->numAllocated = numInterfaces;
175 if (map->numAllocated < numInterfaces) {
176 map = 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 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
195 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
196 ret = ifr.ifr_flags & IFF_LOOPBACK;
201 static void countInterfaces(int fd, caddr_t buf, size_t len)
204 DWORD numNonLoopbackInterfaces = 0, numLoopbackInterfaces = 0;
206 while (ifPtr && ifPtr < buf + len) {
207 struct ifreq *ifr = (struct ifreq *)ifPtr;
209 if (isLoopbackInterface(fd, ifr->ifr_name))
210 numLoopbackInterfaces++;
212 numNonLoopbackInterfaces++;
213 ifPtr += ifreq_len(ifr);
215 gNonLoopbackInterfaceMap = sizeMap(gNonLoopbackInterfaceMap,
216 numNonLoopbackInterfaces);
217 gLoopbackInterfaceMap = sizeMap(gLoopbackInterfaceMap,
218 numLoopbackInterfaces);
221 /* Stores the name in the given map, and increments the map's numInterfaces
222 * member if stored successfully. Will store in the same slot as previously if
223 * usedLastPass is set, otherwise will store in a new slot.
224 * Assumes map and name are not NULL, and the usedLastPass flag is set
225 * correctly for each entry in the map, and that map->numInterfaces <
227 * FIXME: this is kind of expensive, doing a linear scan of the map with a
228 * string comparison of each entry to find the old slot.
230 static void storeInterfaceInMap(InterfaceNameMap *map, const char *name)
236 /* look for previous slot, mark in use if so */
237 for (ndx = 0; !stored && ndx < map->nextAvailable; ndx++) {
238 if (map->table[ndx].usedLastPass && !strncmp(map->table[ndx].name, name,
239 sizeof(map->table[ndx].name))) {
240 map->table[ndx].inUse = TRUE;
244 /* look for new slot */
245 for (ndx = 0; !stored && ndx < map->numAllocated; ndx++) {
246 if (!map->table[ndx].inUse) {
247 lstrcpynA(map->table[ndx].name, name, IFNAMSIZ);
248 map->table[ndx].inUse = TRUE;
250 if (ndx >= map->nextAvailable)
251 map->nextAvailable = ndx + 1;
255 map->numInterfaces++;
259 /* Sets all used entries' usedLastPass flag to their inUse flag, clears
260 * their inUse flag, and clears their numInterfaces member.
262 static void markOldInterfaces(InterfaceNameMap *map)
267 map->numInterfaces = 0;
268 for (ndx = 0; ndx < map->nextAvailable; ndx++) {
269 map->table[ndx].usedLastPass = map->table[ndx].inUse;
270 map->table[ndx].inUse = FALSE;
275 static void classifyInterfaces(int fd, caddr_t buf, size_t len)
279 markOldInterfaces(gNonLoopbackInterfaceMap);
280 markOldInterfaces(gLoopbackInterfaceMap);
281 while (ifPtr && ifPtr < buf + len) {
282 struct ifreq *ifr = (struct ifreq *)ifPtr;
284 if (ifr->ifr_addr.sa_family == AF_INET) {
285 if (isLoopbackInterface(fd, ifr->ifr_name))
286 storeInterfaceInMap(gLoopbackInterfaceMap, ifr->ifr_name);
288 storeInterfaceInMap(gNonLoopbackInterfaceMap, ifr->ifr_name);
290 ifPtr += ifreq_len(ifr);
294 static void enumerateInterfaces(void)
298 fd = socket(PF_INET, SOCK_DGRAM, 0);
300 int ret, guessedNumInterfaces;
303 /* try to avoid silly heap action by starting with the right size buffer */
304 guessedNumInterfaces = 0;
305 if (gNonLoopbackInterfaceMap)
306 guessedNumInterfaces += gNonLoopbackInterfaceMap->numInterfaces;
307 if (gLoopbackInterfaceMap)
308 guessedNumInterfaces += gLoopbackInterfaceMap->numInterfaces;
311 memset(&ifc, 0, sizeof(ifc));
312 /* there is no way to know the interface count beforehand,
313 so we need to loop again and again upping our max each time
314 until returned < max */
316 if (guessedNumInterfaces == 0)
317 guessedNumInterfaces = INITIAL_INTERFACES_ASSUMED;
319 guessedNumInterfaces *= 2;
320 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
321 ifc.ifc_len = sizeof(struct ifreq) * guessedNumInterfaces;
322 ifc.ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc.ifc_len);
323 ret = ioctl(fd, SIOCGIFCONF, &ifc);
325 ifc.ifc_len == (sizeof(struct ifreq) * guessedNumInterfaces));
328 EnterCriticalSection(&mapCS);
329 countInterfaces(fd, ifc.ifc_buf, ifc.ifc_len);
330 classifyInterfaces(fd, ifc.ifc_buf, ifc.ifc_len);
331 LeaveCriticalSection(&mapCS);
334 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
339 DWORD getNumNonLoopbackInterfaces(void)
341 enumerateInterfaces();
342 return gNonLoopbackInterfaceMap ? gNonLoopbackInterfaceMap->numInterfaces : 0;
345 DWORD getNumInterfaces(void)
347 DWORD ret = getNumNonLoopbackInterfaces();
349 ret += gLoopbackInterfaceMap ? gLoopbackInterfaceMap->numInterfaces : 0;
353 const char *getInterfaceNameByIndex(DWORD index)
356 InterfaceNameMap *map;
357 const char *ret = NULL;
359 EnterCriticalSection(&mapCS);
360 if (index & INDEX_IS_LOOPBACK) {
361 realIndex = index ^ INDEX_IS_LOOPBACK;
362 map = gLoopbackInterfaceMap;
366 map = gNonLoopbackInterfaceMap;
368 if (map && realIndex < map->nextAvailable)
369 ret = map->table[realIndex].name;
370 LeaveCriticalSection(&mapCS);
374 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
380 return ERROR_INVALID_PARAMETER;
382 return ERROR_INVALID_PARAMETER;
384 EnterCriticalSection(&mapCS);
385 for (ndx = 0; !found && gNonLoopbackInterfaceMap &&
386 ndx < gNonLoopbackInterfaceMap->nextAvailable; ndx++)
387 if (!strncmp(gNonLoopbackInterfaceMap->table[ndx].name, name, IFNAMSIZ)) {
391 for (ndx = 0; !found && gLoopbackInterfaceMap &&
392 ndx < gLoopbackInterfaceMap->nextAvailable; ndx++)
393 if (!strncmp(gLoopbackInterfaceMap->table[ndx].name, name, IFNAMSIZ)) {
395 *index = ndx | INDEX_IS_LOOPBACK;
397 LeaveCriticalSection(&mapCS);
401 ret = ERROR_INVALID_DATA;
405 static void addMapEntriesToIndexTable(InterfaceIndexTable *table,
406 const InterfaceNameMap *map)
411 for (ndx = 0; ndx < map->nextAvailable &&
412 table->numIndexes < table->numAllocated; ndx++)
413 if (map->table[ndx].inUse) {
414 DWORD externalNdx = ndx;
416 if (map == gLoopbackInterfaceMap)
417 externalNdx |= INDEX_IS_LOOPBACK;
418 table->indexes[table->numIndexes++] = externalNdx;
423 InterfaceIndexTable *getInterfaceIndexTable(void)
426 InterfaceIndexTable *ret;
428 EnterCriticalSection(&mapCS);
429 numInterfaces = getNumInterfaces();
430 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
431 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
433 ret->numAllocated = numInterfaces;
434 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
435 addMapEntriesToIndexTable(ret, gLoopbackInterfaceMap);
437 LeaveCriticalSection(&mapCS);
441 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
444 InterfaceIndexTable *ret;
446 EnterCriticalSection(&mapCS);
447 numInterfaces = getNumNonLoopbackInterfaces();
448 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
449 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
451 ret->numAllocated = numInterfaces;
452 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
454 LeaveCriticalSection(&mapCS);
458 DWORD getInterfaceIPAddrByName(const char *name)
460 DWORD ret = INADDR_ANY;
463 int fd = socket(PF_INET, SOCK_DGRAM, 0);
468 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
469 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0)
470 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
477 DWORD getInterfaceIPAddrByIndex(DWORD index)
480 const char *name = getInterfaceNameByIndex(index);
483 ret = getInterfaceIPAddrByName(name);
489 DWORD getInterfaceBCastAddrByName(const char *name)
491 DWORD ret = INADDR_ANY;
494 int fd = socket(PF_INET, SOCK_DGRAM, 0);
499 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
500 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
501 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
508 DWORD getInterfaceBCastAddrByIndex(DWORD index)
511 const char *name = getInterfaceNameByIndex(index);
514 ret = getInterfaceBCastAddrByName(name);
520 DWORD getInterfaceMaskByName(const char *name)
522 DWORD ret = INADDR_NONE;
525 int fd = socket(PF_INET, SOCK_DGRAM, 0);
530 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
531 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
532 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
539 DWORD getInterfaceMaskByIndex(DWORD index)
542 const char *name = getInterfaceNameByIndex(index);
545 ret = getInterfaceMaskByName(name);
551 #if defined (SIOCGIFHWADDR)
552 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
558 if (!name || !len || !addr || !type)
559 return ERROR_INVALID_PARAMETER;
561 fd = socket(PF_INET, SOCK_DGRAM, 0);
565 memset(&ifr, 0, sizeof(struct ifreq));
566 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
567 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
568 ret = ERROR_INVALID_DATA;
570 unsigned int addrLen;
572 switch (ifr.ifr_hwaddr.sa_family)
574 #ifdef ARPHRD_LOOPBACK
575 case ARPHRD_LOOPBACK:
577 *type = MIB_IF_TYPE_LOOPBACK;
583 *type = MIB_IF_TYPE_ETHERNET;
589 *type = MIB_IF_TYPE_FDDI;
592 #ifdef ARPHRD_IEEE802
593 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
595 *type = MIB_IF_TYPE_TOKENRING;
598 #ifdef ARPHRD_IEEE802_TR
599 case ARPHRD_IEEE802_TR: /* also Token Ring? */
601 *type = MIB_IF_TYPE_TOKENRING;
607 *type = MIB_IF_TYPE_SLIP;
613 *type = MIB_IF_TYPE_PPP;
617 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
618 *type = MIB_IF_TYPE_OTHER;
620 if (addrLen > *len) {
621 ret = ERROR_INSUFFICIENT_BUFFER;
626 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
627 /* zero out remaining bytes for broken implementations */
628 memset(addr + addrLen, 0, *len - addrLen);
636 ret = ERROR_NO_MORE_FILES;
639 #elif defined (SIOCGARP)
640 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
646 if (!name || !len || !addr || !type)
647 return ERROR_INVALID_PARAMETER;
649 fd = socket(PF_INET, SOCK_DGRAM, 0);
651 if (isLoopbackInterface(fd, name)) {
652 *type = MIB_IF_TYPE_LOOPBACK;
653 memset(addr, 0, *len);
659 struct sockaddr_in *saddr;
661 memset(&arp, 0, sizeof(struct arpreq));
662 arp.arp_pa.sa_family = AF_INET;
663 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
664 saddr->sin_family = AF_INET;
665 saddr->sin_addr.s_addr = getInterfaceIPAddrByName(name);
666 if ((ioctl(fd, SIOCGARP, &arp)))
667 ret = ERROR_INVALID_DATA;
669 /* FIXME: heh: who said it was ethernet? */
670 int addrLen = ETH_ALEN;
672 if (addrLen > *len) {
673 ret = ERROR_INSUFFICIENT_BUFFER;
678 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
679 /* zero out remaining bytes for broken implementations */
680 memset(addr + addrLen, 0, *len - addrLen);
682 *type = MIB_IF_TYPE_ETHERNET;
690 ret = ERROR_NO_MORE_FILES;
694 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
695 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
699 struct if_msghdr *ifm;
700 struct sockaddr_dl *sdl;
703 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
707 if (!name || !len || !addr || !type)
708 return ERROR_INVALID_PARAMETER;
710 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
711 return ERROR_NO_MORE_FILES;
713 buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
715 return ERROR_NOT_ENOUGH_MEMORY;
717 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
718 HeapFree(GetProcessHeap(), 0, buf);
719 return ERROR_NO_MORE_FILES;
722 ret = ERROR_INVALID_DATA;
723 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
724 ifm = (struct if_msghdr *)p;
725 sdl = (struct sockaddr_dl *)(ifm + 1);
727 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
730 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
731 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
735 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
736 if (addrLen > *len) {
737 ret = ERROR_INSUFFICIENT_BUFFER;
742 memcpy(addr, LLADDR(sdl), addrLen);
743 /* zero out remaining bytes for broken implementations */
744 memset(addr + addrLen, 0, *len - addrLen);
746 #if defined(HAVE_NET_IF_TYPES_H)
747 switch (sdl->sdl_type)
750 *type = MIB_IF_TYPE_ETHERNET;
753 *type = MIB_IF_TYPE_FDDI;
755 case IFT_ISO88024: /* Token Bus */
756 *type = MIB_IF_TYPE_TOKENRING;
758 case IFT_ISO88025: /* Token Ring */
759 *type = MIB_IF_TYPE_TOKENRING;
762 *type = MIB_IF_TYPE_PPP;
765 *type = MIB_IF_TYPE_SLIP;
768 *type = MIB_IF_TYPE_LOOPBACK;
771 *type = MIB_IF_TYPE_OTHER;
774 /* default if we don't know */
775 *type = MIB_IF_TYPE_ETHERNET;
780 HeapFree(GetProcessHeap(), 0, buf);
785 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
788 const char *name = getInterfaceNameByIndex(index);
791 return getInterfacePhysicalByName(name, len, addr, type);
793 return ERROR_INVALID_DATA;
796 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
802 return ERROR_INVALID_PARAMETER;
804 return ERROR_INVALID_PARAMETER;
806 fd = socket(PF_INET, SOCK_DGRAM, 0);
810 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
811 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
812 ret = ERROR_INVALID_DATA;
817 *mtu = ifr.ifr_metric;
823 ret = ERROR_NO_MORE_FILES;
827 DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu)
829 const char *name = getInterfaceNameByIndex(index);
832 return getInterfaceMtuByName(name, mtu);
834 return ERROR_INVALID_DATA;
837 DWORD getInterfaceStatusByName(const char *name, PDWORD status)
843 return ERROR_INVALID_PARAMETER;
845 return ERROR_INVALID_PARAMETER;
847 fd = socket(PF_INET, SOCK_DGRAM, 0);
851 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
852 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
853 ret = ERROR_INVALID_DATA;
855 if (ifr.ifr_flags & IFF_UP)
856 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
858 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
863 ret = ERROR_NO_MORE_FILES;
867 DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status)
869 const char *name = getInterfaceNameByIndex(index);
872 return getInterfaceStatusByName(name, status);
874 return ERROR_INVALID_DATA;
877 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
879 BYTE addr[MAX_INTERFACE_PHYSADDR];
880 DWORD ret, len = sizeof(addr), type;
883 return ERROR_INVALID_PARAMETER;
885 return ERROR_INVALID_PARAMETER;
887 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
891 memset(entry, 0, sizeof(MIB_IFROW));
892 for (assigner = entry->wszName, walker = name; *walker;
893 walker++, assigner++)
896 getInterfaceIndexByName(name, &entry->dwIndex);
897 entry->dwPhysAddrLen = len;
898 memcpy(entry->bPhysAddr, addr, len);
899 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
900 entry->dwType = type;
901 /* FIXME: how to calculate real speed? */
902 getInterfaceMtuByName(name, &entry->dwMtu);
903 /* lie, there's no "administratively down" here */
904 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
905 getInterfaceStatusByName(name, &entry->dwOperStatus);
906 /* punt on dwLastChange? */
907 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
908 memcpy(entry->bDescr, name, entry->dwDescrLen);
909 entry->bDescr[entry->dwDescrLen] = '\0';
914 ret = ERROR_INVALID_DATA;
918 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
920 const char *name = getInterfaceNameByIndex(index);
923 return getInterfaceEntryByName(name, entry);
925 return ERROR_INVALID_DATA;
928 char *toIPAddressString(unsigned int addr, char string[16])
931 struct in_addr iAddr;
934 /* extra-anal, just to make auditors happy */
935 lstrcpynA(string, inet_ntoa(iAddr), 16);