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 * But here's a problem with doing so:
31 * - Netbios() has a concept of an LAN adapter number (LANA), which is an 8-bit
32 * number in the range 0-254, inclusive. The MSDN pages for Netbios() says
33 * the original Netbios() spec allowed only 0 or 1 to be used, though "new"
34 * applications should enumerate available adapters rather than assuming 0
35 * is the default adapter.
36 * I'm concerned that some old application might depend on being able to get
37 * "the" MAC address of a machine by opening LANA 0 and getting its MAC
38 * address. This also implies LANA 0 should correspond to a non-loopback
40 * On Linux, the if_nametoindex index is 1-based, and "lo" typically has
42 * I could make netapi32 do its own LANA map, independent of my index
43 * assignment, but it seems simpler just to assign 0-based indexes and put
44 * non-loopback adapters first, so the first 255 indexes (!) on a system will
45 * automatically map to LANA numbers without difficulty.
46 * - One more argument for doing it this way, if you don't buy the Netbios()
47 * argument: WsControl() (in wsock32) uses the same index to refer to an IP
48 * address and an interface. If I assigned multiple IP addresses to an
49 * interface, wsock32 would have to maintain a table of IP addresses with its
50 * own indexing scheme. No thanks.
52 * There are three implemened methods for determining the MAC address of an
54 * - a specific IOCTL (Linux)
55 * - looking in the ARP cache (at least Solaris)
56 * - using the sysctl interface (FreeBSD and MacOSX)
57 * Solaris and some others have SIOCGENADDR, but I haven't gotten that to work
58 * on the Solaris boxes at SourceForge's compile farm, whereas SIOCGARP does.
72 #include <sys/types.h>
74 #ifdef HAVE_SYS_SOCKET_H
75 #include <sys/socket.h>
78 #ifdef HAVE_NETINET_IN_H
79 #include <netinet/in.h>
82 #ifdef HAVE_ARPA_INET_H
83 #include <arpa/inet.h>
90 #ifdef HAVE_NET_IF_ARP_H
91 #include <net/if_arp.h>
94 #ifdef HAVE_NET_ROUTE_H
95 #include <net/route.h>
98 #ifdef HAVE_SYS_IOCTL_H
99 #include <sys/ioctl.h>
102 #ifdef HAVE_SYS_SYSCTL_H
103 #include <sys/sysctl.h>
106 #ifdef HAVE_SYS_SOCKIO_H
107 #include <sys/sockio.h>
110 #ifdef HAVE_NET_IF_DL_H
111 #include <net/if_dl.h>
114 #ifdef HAVE_NET_IF_TYPES_H
115 #include <net/if_types.h>
120 #include "iprtrmib.h"
123 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
124 #define ifreq_len(ifr) \
125 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
127 #define ifreq_len(ifr) sizeof(struct ifreq)
135 #define INADDR_NONE (~0U)
138 #define INITIAL_INTERFACES_ASSUMED 4
140 #define INDEX_IS_LOOPBACK 0x00800000
142 /* Type declarations */
144 typedef struct _InterfaceNameMapEntry {
148 } InterfaceNameMapEntry;
150 typedef struct _InterfaceNameMap {
154 InterfaceNameMapEntry table[1];
157 /* Global variables */
159 static InterfaceNameMap *gNonLoopbackInterfaceMap = NULL;
160 static InterfaceNameMap *gLoopbackInterfaceMap = NULL;
164 /* Sizes the passed-in map to have enough space for numInterfaces interfaces.
165 * If map is NULL, allocates a new map. If it is not, may reallocate the
166 * existing map and return a map of increased size. Returns the allocated map,
167 * or NULL if it could not allocate a map of the requested size.
169 InterfaceNameMap *sizeMap(InterfaceNameMap *map, DWORD numInterfaces)
172 numInterfaces = max(numInterfaces, INITIAL_INTERFACES_ASSUMED);
173 map = (InterfaceNameMap *)calloc(1, sizeof(InterfaceNameMap) +
174 (numInterfaces - 1) * sizeof(InterfaceNameMapEntry));
176 map->numAllocated = numInterfaces;
179 if (map->numAllocated < numInterfaces) {
180 map = (InterfaceNameMap *)realloc(map, sizeof(InterfaceNameMap) +
181 (numInterfaces - 1) * sizeof(InterfaceNameMapEntry));
183 memset(&map->table[map->numAllocated], 0,
184 (numInterfaces - map->numAllocated) * sizeof(InterfaceNameMapEntry));
190 static int isLoopbackInterface(int fd, const char *name)
197 strncpy(ifr.ifr_name, name, IFNAMSIZ);
198 ifr.ifr_name[IFNAMSIZ-1] = '\0';
199 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
200 ret = ifr.ifr_flags & IFF_LOOPBACK;
205 static void countInterfaces(int fd, caddr_t buf, size_t len)
208 DWORD numNonLoopbackInterfaces = 0, numLoopbackInterfaces = 0;
210 while (ifPtr && ifPtr < buf + len) {
211 struct ifreq *ifr = (struct ifreq *)ifPtr;
213 if (isLoopbackInterface(fd, ifr->ifr_name))
214 numLoopbackInterfaces++;
216 numNonLoopbackInterfaces++;
217 ifPtr += ifreq_len(ifr);
219 gNonLoopbackInterfaceMap = sizeMap(gNonLoopbackInterfaceMap,
220 numNonLoopbackInterfaces);
221 gLoopbackInterfaceMap = sizeMap(gLoopbackInterfaceMap,
222 numLoopbackInterfaces);
225 /* Stores the name in the given map, and increments the map's numInterfaces
226 * member if stored successfully. Will store in the same slot as previously if
227 * usedLastPass is set, otherwise will store in a new slot.
228 * Assumes map and name are not NULL, and the usedLastPass flag is set
229 * correctly for each entry in the map, and that map->numInterfaces <
231 * FIXME: this is kind of expensive, doing a linear scan of the map with a
232 * string comparison of each entry to find the old slot.
234 static void storeInterfaceInMap(InterfaceNameMap *map, const char *name)
240 /* look for previous slot, mark in use if so */
241 for (ndx = 0; !stored && ndx < map->nextAvailable; ndx++) {
242 if (map->table[ndx].usedLastPass && !strncmp(map->table[ndx].name, name,
243 sizeof(map->table[ndx].name))) {
244 map->table[ndx].inUse = TRUE;
248 /* look for new slot */
249 for (ndx = 0; !stored && ndx < map->numAllocated; ndx++) {
250 if (!map->table[ndx].inUse) {
251 strncpy(map->table[ndx].name, name, IFNAMSIZ);
252 map->table[ndx].name[IFNAMSIZ-1] = '\0';
253 map->table[ndx].inUse = TRUE;
255 if (ndx >= map->nextAvailable)
256 map->nextAvailable = ndx + 1;
260 map->numInterfaces++;
264 /* Sets all used entries' usedLastPass flag to their inUse flag, clears
265 * their inUse flag, and clears their numInterfaces member.
267 static void markOldInterfaces(InterfaceNameMap *map)
272 map->numInterfaces = 0;
273 for (ndx = 0; ndx < map->nextAvailable; ndx++) {
274 map->table[ndx].usedLastPass = map->table[ndx].inUse;
275 map->table[ndx].inUse = FALSE;
280 static void classifyInterfaces(int fd, caddr_t buf, size_t len)
284 markOldInterfaces(gNonLoopbackInterfaceMap);
285 markOldInterfaces(gLoopbackInterfaceMap);
286 while (ifPtr && ifPtr < buf + len) {
287 struct ifreq *ifr = (struct ifreq *)ifPtr;
289 if (isLoopbackInterface(fd, ifr->ifr_name))
290 storeInterfaceInMap(gLoopbackInterfaceMap, ifr->ifr_name);
292 storeInterfaceInMap(gNonLoopbackInterfaceMap, ifr->ifr_name);
293 ifPtr += ifreq_len(ifr);
297 static void enumerateInterfaces(void)
301 fd = socket(PF_INET, SOCK_DGRAM, 0);
303 int ret, guessedNumInterfaces;
306 /* try to avoid silly heap action by starting with the right size buffer */
307 guessedNumInterfaces = 0;
308 if (gNonLoopbackInterfaceMap)
309 guessedNumInterfaces += gNonLoopbackInterfaceMap->numInterfaces;
310 if (gLoopbackInterfaceMap)
311 guessedNumInterfaces += gLoopbackInterfaceMap->numInterfaces;
314 memset(&ifc, 0, sizeof(ifc));
315 /* there is no way to know the interface count beforehand,
316 so we need to loop again and again upping our max each time
317 until returned < max */
319 if (guessedNumInterfaces == 0)
320 guessedNumInterfaces = INITIAL_INTERFACES_ASSUMED;
322 guessedNumInterfaces *= 2;
325 ifc.ifc_len = sizeof(struct ifreq) * guessedNumInterfaces;
326 ifc.ifc_buf = (char *)malloc(ifc.ifc_len);
327 ret = ioctl(fd, SIOCGIFCONF, &ifc);
329 ifc.ifc_len == (sizeof(struct ifreq) * guessedNumInterfaces));
332 countInterfaces(fd, ifc.ifc_buf, ifc.ifc_len);
333 classifyInterfaces(fd, ifc.ifc_buf, ifc.ifc_len);
342 DWORD getNumNonLoopbackInterfaces(void)
344 enumerateInterfaces();
345 return gNonLoopbackInterfaceMap ? gNonLoopbackInterfaceMap->numInterfaces : 0;
348 DWORD getNumInterfaces(void)
350 DWORD ret = getNumNonLoopbackInterfaces();
352 ret += gLoopbackInterfaceMap ? gLoopbackInterfaceMap->numInterfaces : 0;
356 const char *getInterfaceNameByIndex(DWORD index)
359 InterfaceNameMap *map;
360 const char *ret = NULL;
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;
375 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
381 return ERROR_INVALID_PARAMETER;
383 return ERROR_INVALID_PARAMETER;
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;
400 return ERROR_INVALID_DATA;
403 static void addMapEntriesToIndexTable(InterfaceIndexTable *table,
404 const InterfaceNameMap *map)
409 for (ndx = 0; ndx < map->nextAvailable &&
410 table->numIndexes < table->numAllocated; ndx++)
411 if (map->table[ndx].inUse) {
412 DWORD externalNdx = ndx;
414 if (map == gLoopbackInterfaceMap)
415 externalNdx |= INDEX_IS_LOOPBACK;
416 table->indexes[table->numIndexes++] = externalNdx;
421 InterfaceIndexTable *getInterfaceIndexTable(void)
423 DWORD numInterfaces = getNumInterfaces();
424 InterfaceIndexTable *ret = (InterfaceIndexTable *)calloc(1,
425 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
428 ret->numAllocated = numInterfaces;
429 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
430 addMapEntriesToIndexTable(ret, gLoopbackInterfaceMap);
435 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
437 DWORD numInterfaces = getNumNonLoopbackInterfaces();
438 InterfaceIndexTable *ret = (InterfaceIndexTable *)calloc(1,
439 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
442 ret->numAllocated = numInterfaces;
443 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
448 DWORD getInterfaceIPAddrByName(const char *name)
450 DWORD ret = INADDR_ANY;
453 int fd = socket(PF_INET, SOCK_DGRAM, 0);
458 strncpy(ifr.ifr_name, name, IFNAMSIZ);
459 ifr.ifr_name[IFNAMSIZ-1] = '\0';
460 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0)
461 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
468 DWORD getInterfaceIPAddrByIndex(DWORD index)
471 const char *name = getInterfaceNameByIndex(index);
474 ret = getInterfaceIPAddrByName(name);
480 DWORD getInterfaceBCastAddrByName(const char *name)
482 DWORD ret = INADDR_ANY;
485 int fd = socket(PF_INET, SOCK_DGRAM, 0);
490 strncpy(ifr.ifr_name, name, IFNAMSIZ);
491 ifr.ifr_name[IFNAMSIZ-1] = '\0';
492 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
493 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
500 DWORD getInterfaceBCastAddrByIndex(DWORD index)
503 const char *name = getInterfaceNameByIndex(index);
506 ret = getInterfaceBCastAddrByName(name);
512 DWORD getInterfaceMaskByName(const char *name)
514 DWORD ret = INADDR_NONE;
517 int fd = socket(PF_INET, SOCK_DGRAM, 0);
522 strncpy(ifr.ifr_name, name, IFNAMSIZ);
523 ifr.ifr_name[IFNAMSIZ-1] = '\0';
524 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
525 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
532 DWORD getInterfaceMaskByIndex(DWORD index)
535 const char *name = getInterfaceNameByIndex(index);
538 ret = getInterfaceMaskByName(name);
544 #if defined (SIOCGIFHWADDR)
545 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
551 if (!name || !len || !addr || !type)
552 return ERROR_INVALID_PARAMETER;
554 fd = socket(PF_INET, SOCK_DGRAM, 0);
558 memset(&ifr, 0, sizeof(struct ifreq));
559 strncpy(ifr.ifr_name, name, IFNAMSIZ);
560 ifr.ifr_name[IFNAMSIZ-1] = '\0';
561 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
562 ret = ERROR_INVALID_DATA;
566 switch (ifr.ifr_hwaddr.sa_family)
568 case ARPHRD_LOOPBACK:
570 *type = MIB_IF_TYPE_LOOPBACK;
574 *type = MIB_IF_TYPE_ETHERNET;
578 *type = MIB_IF_TYPE_FDDI;
580 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
582 *type = MIB_IF_TYPE_TOKENRING;
584 case ARPHRD_IEEE802_TR: /* also Token Ring? */
586 *type = MIB_IF_TYPE_TOKENRING;
590 *type = MIB_IF_TYPE_SLIP;
594 *type = MIB_IF_TYPE_PPP;
597 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
598 *type = MIB_IF_TYPE_OTHER;
600 if (addrLen > *len) {
601 ret = ERROR_INSUFFICIENT_BUFFER;
606 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
607 /* zero out remaining bytes for broken implementations */
608 memset(addr + addrLen, 0, *len - addrLen);
616 ret = ERROR_NO_MORE_FILES;
619 #elif defined (SIOCGARP)
620 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
626 if (!name || !len || !addr || !type)
627 return ERROR_INVALID_PARAMETER;
629 fd = socket(PF_INET, SOCK_DGRAM, 0);
631 if (isLoopbackInterface(fd, name)) {
632 *type = MIB_IF_TYPE_LOOPBACK;
633 memset(addr, 0, *len);
639 struct sockaddr_in *saddr;
641 memset(&arp, 0, sizeof(struct arpreq));
642 arp.arp_pa.sa_family = AF_INET;
643 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
644 saddr->sin_family = AF_INET;
645 saddr->sin_addr.s_addr = getInterfaceIPAddrByName(name);
646 if ((ioctl(fd, SIOCGARP, &arp)))
647 ret = ERROR_INVALID_DATA;
649 /* FIXME: heh: who said it was ethernet? */
650 int addrLen = ETH_ALEN;
652 if (addrLen > *len) {
653 ret = ERROR_INSUFFICIENT_BUFFER;
658 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
659 /* zero out remaining bytes for broken implementations */
660 memset(addr + addrLen, 0, *len - addrLen);
662 *type = MIB_IF_TYPE_ETHERNET;
670 ret = ERROR_NO_MORE_FILES;
674 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
675 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
679 struct if_msghdr *ifm;
680 struct sockaddr_dl *sdl;
683 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
687 if (!name || !len || !addr || !type)
688 return ERROR_INVALID_PARAMETER;
690 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
691 return ERROR_NO_MORE_FILES;
693 buf = (u_char *)malloc(mibLen);
695 return ERROR_NOT_ENOUGH_MEMORY;
697 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
699 return ERROR_NO_MORE_FILES;
702 ret = ERROR_INVALID_DATA;
703 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
704 ifm = (struct if_msghdr *)p;
705 sdl = (struct sockaddr_dl *)(ifm + 1);
707 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
710 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
711 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
715 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
716 if (addrLen > *len) {
717 ret = ERROR_INSUFFICIENT_BUFFER;
722 memcpy(addr, LLADDR(sdl), addrLen);
723 /* zero out remaining bytes for broken implementations */
724 memset(addr + addrLen, 0, *len - addrLen);
726 #if defined(HAVE_NET_IF_TYPES_H)
727 switch (sdl->sdl_type)
730 *type = MIB_IF_TYPE_ETHERNET;
733 *type = MIB_IF_TYPE_FDDI;
735 case IFT_ISO88024: /* Token Bus */
736 *type = MIB_IF_TYPE_TOKENRING;
738 case IFT_ISO88025: /* Token Ring */
739 *type = MIB_IF_TYPE_TOKENRING;
742 *type = MIB_IF_TYPE_PPP;
745 *type = MIB_IF_TYPE_SLIP;
748 *type = MIB_IF_TYPE_LOOPBACK;
751 *type = MIB_IF_TYPE_OTHER;
754 /* default if we don't know */
755 *type = MIB_IF_TYPE_ETHERNET;
765 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
768 const char *name = getInterfaceNameByIndex(index);
771 return getInterfacePhysicalByName(name, len, addr, type);
773 return ERROR_INVALID_DATA;
776 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
782 return ERROR_INVALID_PARAMETER;
784 return ERROR_INVALID_PARAMETER;
786 fd = socket(PF_INET, SOCK_DGRAM, 0);
790 strncpy(ifr.ifr_name, name, IFNAMSIZ);
791 ifr.ifr_name[IFNAMSIZ-1] = '\0';
792 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
793 ret = ERROR_INVALID_DATA;
800 ret = ERROR_NO_MORE_FILES;
804 DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu)
806 const char *name = getInterfaceNameByIndex(index);
809 return getInterfaceMtuByName(name, mtu);
811 return ERROR_INVALID_DATA;
814 DWORD getInterfaceStatusByName(const char *name, PDWORD status)
820 return ERROR_INVALID_PARAMETER;
822 return ERROR_INVALID_PARAMETER;
824 fd = socket(PF_INET, SOCK_DGRAM, 0);
828 strncpy(ifr.ifr_name, name, IFNAMSIZ);
829 ifr.ifr_name[IFNAMSIZ-1] = '\0';
830 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
831 ret = ERROR_INVALID_DATA;
833 if (ifr.ifr_flags & IFF_UP)
834 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
836 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
841 ret = ERROR_NO_MORE_FILES;
845 DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status)
847 const char *name = getInterfaceNameByIndex(index);
850 return getInterfaceStatusByName(name, status);
852 return ERROR_INVALID_DATA;
855 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
857 BYTE addr[MAX_INTERFACE_PHYSADDR];
858 DWORD ret, len = sizeof(addr), type;
861 return ERROR_INVALID_PARAMETER;
863 return ERROR_INVALID_PARAMETER;
865 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
869 memset(entry, 0, sizeof(MIB_IFROW));
870 for (assigner = entry->wszName, walker = name; *walker;
871 walker++, assigner++)
874 getInterfaceIndexByName(name, &entry->dwIndex);
875 entry->dwPhysAddrLen = len;
876 memcpy(entry->bPhysAddr, addr, len);
877 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
878 entry->dwType = type;
879 /* FIXME: how to calculate real speed? */
880 getInterfaceMtuByName(name, &entry->dwMtu);
881 /* lie, there's no "administratively down" here */
882 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
883 getInterfaceStatusByName(name, &entry->dwOperStatus);
884 /* punt on dwLastChange? */
885 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
886 memcpy(entry->bDescr, name, entry->dwDescrLen);
887 entry->bDescr[entry->dwDescrLen] = '\0';
892 ret = ERROR_INVALID_DATA;
896 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
898 const char *name = getInterfaceNameByIndex(index);
901 return getInterfaceEntryByName(name, entry);
903 return ERROR_INVALID_DATA;
906 char *toIPAddressString(unsigned int addr, char string[16])
909 struct in_addr iAddr;
912 /* extra-anal, just to make auditors happy */
913 strncpy(string, inet_ntoa(iAddr), 16);