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.
71 #include <sys/types.h>
74 #include <sys/socket.h>
78 #include <netinet/in.h>
82 #include <arpa/inet.h>
90 #include <net/if_arp.h>
94 #include <net/route.h>
98 #include <sys/ioctl.h>
101 #if HAVE_SYS_SYSCTL_H
102 #include <sys/sysctl.h>
105 #if HAVE_SYS_SOCKIO_H
106 #include <sys/sockio.h>
110 #include <net/if_dl.h>
113 #if HAVE_NET_IF_TYPES_H
114 #include <net/if_types.h>
118 #include "iprtrmib.h"
121 #if HAVE_STRUCT_SOCKADDR_SA_LEN
122 #define ifreq_len(ifr) \
123 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
125 #define ifreq_len(ifr) sizeof(struct ifreq)
133 #define INADDR_NONE (~0U)
136 #define INITIAL_INTERFACES_ASSUMED 4
138 #define INDEX_IS_LOOPBACK 0x00800000
140 /* Type declarations */
142 typedef struct _InterfaceNameMapEntry {
146 } InterfaceNameMapEntry;
148 typedef struct _InterfaceNameMap {
152 InterfaceNameMapEntry table[1];
155 /* Global variables */
157 static InterfaceNameMap *gNonLoopbackInterfaceMap = NULL;
158 static InterfaceNameMap *gLoopbackInterfaceMap = NULL;
162 /* Sizes the passed-in map to have enough space for numInterfaces interfaces.
163 * If map is NULL, allocates a new map. If it is not, may reallocate the
164 * existing map and return a map of increased size. Returns the allocated map,
165 * or NULL if it could not allocate a map of the requested size.
167 InterfaceNameMap *sizeMap(InterfaceNameMap *map, DWORD numInterfaces)
170 numInterfaces = max(numInterfaces, INITIAL_INTERFACES_ASSUMED);
171 map = (InterfaceNameMap *)calloc(1, sizeof(InterfaceNameMap) +
172 (numInterfaces - 1) * sizeof(InterfaceNameMapEntry));
174 map->numAllocated = numInterfaces;
177 if (map->numAllocated < numInterfaces) {
178 map = (InterfaceNameMap *)realloc(map, sizeof(InterfaceNameMap) +
179 (numInterfaces - 1) * sizeof(InterfaceNameMapEntry));
181 memset(&map->table[map->numAllocated], 0,
182 (numInterfaces - map->numAllocated) * sizeof(InterfaceNameMapEntry));
188 static int isLoopbackInterface(int fd, const char *name)
195 strncpy(ifr.ifr_name, name, IFNAMSIZ);
196 ifr.ifr_name[IFNAMSIZ-1] = '\0';
197 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
198 ret = ifr.ifr_flags & IFF_LOOPBACK;
203 static void countInterfaces(int fd, caddr_t buf, size_t len)
206 DWORD numNonLoopbackInterfaces = 0, numLoopbackInterfaces = 0;
208 while (ifPtr && ifPtr < buf + len) {
209 struct ifreq *ifr = (struct ifreq *)ifPtr;
211 if (isLoopbackInterface(fd, ifr->ifr_name))
212 numLoopbackInterfaces++;
214 numNonLoopbackInterfaces++;
215 ifPtr += ifreq_len(ifr);
217 gNonLoopbackInterfaceMap = sizeMap(gNonLoopbackInterfaceMap,
218 numNonLoopbackInterfaces);
219 gLoopbackInterfaceMap = sizeMap(gLoopbackInterfaceMap,
220 numLoopbackInterfaces);
223 /* Stores the name in the given map, and increments the map's numInterfaces
224 * member if stored successfully. Will store in the same slot as previously if
225 * usedLastPass is set, otherwise will store in a new slot.
226 * Assumes map and name are not NULL, and the usedLastPass flag is set
227 * correctly for each entry in the map, and that map->numInterfaces <
229 * FIXME: this is kind of expensive, doing a linear scan of the map with a
230 * string comparison of each entry to find the old slot.
232 static void storeInterfaceInMap(InterfaceNameMap *map, const char *name)
238 /* look for previous slot, mark in use if so */
239 for (ndx = 0; !stored && ndx < map->nextAvailable; ndx++) {
240 if (map->table[ndx].usedLastPass && !strncmp(map->table[ndx].name, name,
241 sizeof(map->table[ndx].name))) {
242 map->table[ndx].inUse = TRUE;
246 /* look for new slot */
247 for (ndx = 0; !stored && ndx < map->numAllocated; ndx++) {
248 if (!map->table[ndx].inUse) {
249 strncpy(map->table[ndx].name, name, IFNAMSIZ);
250 map->table[ndx].name[IFNAMSIZ-1] = '\0';
251 map->table[ndx].inUse = TRUE;
253 if (ndx >= map->nextAvailable)
254 map->nextAvailable = ndx + 1;
258 map->numInterfaces++;
262 /* Sets all used entries' usedLastPass flag to their inUse flag, clears
263 * their inUse flag, and clears their numInterfaces member.
265 static void markOldInterfaces(InterfaceNameMap *map)
270 map->numInterfaces = 0;
271 for (ndx = 0; ndx < map->nextAvailable; ndx++) {
272 map->table[ndx].usedLastPass = map->table[ndx].inUse;
273 map->table[ndx].inUse = FALSE;
278 static void classifyInterfaces(int fd, caddr_t buf, size_t len)
282 markOldInterfaces(gNonLoopbackInterfaceMap);
283 markOldInterfaces(gLoopbackInterfaceMap);
284 while (ifPtr && ifPtr < buf + len) {
285 struct ifreq *ifr = (struct ifreq *)ifPtr;
287 if (isLoopbackInterface(fd, ifr->ifr_name))
288 storeInterfaceInMap(gLoopbackInterfaceMap, ifr->ifr_name);
290 storeInterfaceInMap(gNonLoopbackInterfaceMap, ifr->ifr_name);
291 ifPtr += ifreq_len(ifr);
295 static void enumerateInterfaces(void)
299 fd = socket(PF_INET, SOCK_DGRAM, 0);
301 int ret, guessedNumInterfaces;
304 /* try to avoid silly heap action by starting with the right size buffer */
305 guessedNumInterfaces = 0;
306 if (gNonLoopbackInterfaceMap)
307 guessedNumInterfaces += gNonLoopbackInterfaceMap->numInterfaces;
308 if (gLoopbackInterfaceMap)
309 guessedNumInterfaces += gLoopbackInterfaceMap->numInterfaces;
312 memset(&ifc, 0, sizeof(ifc));
313 /* there is no way to know the interface count beforehand,
314 so we need to loop again and again upping our max each time
315 until returned < max */
317 if (guessedNumInterfaces == 0)
318 guessedNumInterfaces = INITIAL_INTERFACES_ASSUMED;
320 guessedNumInterfaces *= 2;
323 ifc.ifc_len = sizeof(struct ifreq) * guessedNumInterfaces;
324 ifc.ifc_buf = (char *)malloc(ifc.ifc_len);
325 ret = ioctl(fd, SIOCGIFCONF, &ifc);
327 ifc.ifc_len == (sizeof(struct ifreq) * guessedNumInterfaces));
330 countInterfaces(fd, ifc.ifc_buf, ifc.ifc_len);
331 classifyInterfaces(fd, ifc.ifc_buf, ifc.ifc_len);
340 DWORD getNumNonLoopbackInterfaces(void)
342 enumerateInterfaces();
343 return gNonLoopbackInterfaceMap ? gNonLoopbackInterfaceMap->numInterfaces : 0;
346 DWORD getNumInterfaces(void)
348 DWORD ret = getNumNonLoopbackInterfaces();
350 ret += gLoopbackInterfaceMap ? gLoopbackInterfaceMap->numInterfaces : 0;
354 const char *getInterfaceNameByIndex(DWORD index)
357 InterfaceNameMap *map;
358 const char *ret = NULL;
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;
373 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
379 return ERROR_INVALID_PARAMETER;
381 return ERROR_INVALID_PARAMETER;
383 for (ndx = 0; !found && gNonLoopbackInterfaceMap &&
384 ndx < gNonLoopbackInterfaceMap->nextAvailable; ndx++)
385 if (!strncmp(gNonLoopbackInterfaceMap->table[ndx].name, name, IFNAMSIZ)) {
389 for (ndx = 0; !found && gLoopbackInterfaceMap &&
390 ndx < gLoopbackInterfaceMap->nextAvailable; ndx++)
391 if (!strncmp(gLoopbackInterfaceMap->table[ndx].name, name, IFNAMSIZ)) {
393 *index = ndx | INDEX_IS_LOOPBACK;
398 return ERROR_INVALID_DATA;
401 static void addMapEntriesToIndexTable(InterfaceIndexTable *table,
402 const InterfaceNameMap *map)
407 for (ndx = 0; ndx < map->nextAvailable &&
408 table->numIndexes < table->numAllocated; ndx++)
409 if (map->table[ndx].inUse) {
410 DWORD externalNdx = ndx;
412 if (map == gLoopbackInterfaceMap)
413 externalNdx |= INDEX_IS_LOOPBACK;
414 table->indexes[table->numIndexes++] = externalNdx;
419 InterfaceIndexTable *getInterfaceIndexTable(void)
421 DWORD numInterfaces = getNumInterfaces();
422 InterfaceIndexTable *ret = (InterfaceIndexTable *)calloc(1,
423 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
426 ret->numAllocated = numInterfaces;
427 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
428 addMapEntriesToIndexTable(ret, gLoopbackInterfaceMap);
433 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
435 DWORD numInterfaces = getNumNonLoopbackInterfaces();
436 InterfaceIndexTable *ret = (InterfaceIndexTable *)calloc(1,
437 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
440 ret->numAllocated = numInterfaces;
441 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
446 DWORD getInterfaceIPAddrByName(const char *name)
448 DWORD ret = INADDR_ANY;
451 int fd = socket(PF_INET, SOCK_DGRAM, 0);
456 strncpy(ifr.ifr_name, name, IFNAMSIZ);
457 ifr.ifr_name[IFNAMSIZ-1] = '\0';
458 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0)
459 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
466 DWORD getInterfaceIPAddrByIndex(DWORD index)
469 const char *name = getInterfaceNameByIndex(index);
472 ret = getInterfaceIPAddrByName(name);
478 DWORD getInterfaceBCastAddrByName(const char *name)
480 DWORD ret = INADDR_ANY;
483 int fd = socket(PF_INET, SOCK_DGRAM, 0);
488 strncpy(ifr.ifr_name, name, IFNAMSIZ);
489 ifr.ifr_name[IFNAMSIZ-1] = '\0';
490 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
491 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
498 DWORD getInterfaceBCastAddrByIndex(DWORD index)
501 const char *name = getInterfaceNameByIndex(index);
504 ret = getInterfaceBCastAddrByName(name);
510 DWORD getInterfaceMaskByName(const char *name)
512 DWORD ret = INADDR_NONE;
515 int fd = socket(PF_INET, SOCK_DGRAM, 0);
520 strncpy(ifr.ifr_name, name, IFNAMSIZ);
521 ifr.ifr_name[IFNAMSIZ-1] = '\0';
522 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
523 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
530 DWORD getInterfaceMaskByIndex(DWORD index)
533 const char *name = getInterfaceNameByIndex(index);
536 ret = getInterfaceMaskByName(name);
542 #if defined (SIOCGIFHWADDR)
543 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
549 if (!name || !len || !addr || !type)
550 return ERROR_INVALID_PARAMETER;
552 fd = socket(PF_INET, SOCK_DGRAM, 0);
556 memset(&ifr, 0, sizeof(struct ifreq));
557 strncpy(ifr.ifr_name, name, IFNAMSIZ);
558 ifr.ifr_name[IFNAMSIZ-1] = '\0';
559 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
560 ret = ERROR_INVALID_DATA;
564 switch (ifr.ifr_hwaddr.sa_family)
566 case ARPHRD_LOOPBACK:
568 *type = MIB_IF_TYPE_LOOPBACK;
572 *type = MIB_IF_TYPE_ETHERNET;
576 *type = MIB_IF_TYPE_FDDI;
578 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
580 *type = MIB_IF_TYPE_TOKENRING;
582 case ARPHRD_IEEE802_TR: /* also Token Ring? */
584 *type = MIB_IF_TYPE_TOKENRING;
588 *type = MIB_IF_TYPE_SLIP;
592 *type = MIB_IF_TYPE_PPP;
595 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
596 *type = MIB_IF_TYPE_OTHER;
598 if (addrLen > *len) {
599 ret = ERROR_INSUFFICIENT_BUFFER;
604 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
605 /* zero out remaining bytes for broken implementations */
606 memset(addr + addrLen, 0, *len - addrLen);
614 ret = ERROR_NO_MORE_FILES;
617 #elif defined (SIOCGARP)
618 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
624 if (!name || !len || !addr || !type)
625 return ERROR_INVALID_PARAMETER;
627 fd = socket(PF_INET, SOCK_DGRAM, 0);
629 if (isLoopbackInterface(fd, name)) {
630 *type = MIB_IF_TYPE_LOOPBACK;
631 memset(addr, 0, *len);
636 struct sockaddr_in *saddr;
638 memset(&arp, 0, sizeof(struct arpreq));
639 arp.arp_pa.sa_family = AF_INET;
640 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
641 saddr->sin_family = AF_INET;
642 saddr->sin_addr.s_addr = getInterfaceAddrByName(name);
643 if ((ioctl(fd, SIOCGARP, &arp)))
644 ret = ERROR_INVALID_DATA;
646 /* FIXME: heh: who said it was ethernet? */
647 int addrLen = ETH_ALEN;
649 if (addrLen > *len) {
650 ret = ERROR_INSUFFICIENT_BUFFER;
655 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
656 /* zero out remaining bytes for broken implementations */
657 memset(addr + addrLen, 0, *len - addrLen);
659 *type = MIB_IF_TYPE_ETHERNET;
665 ret = ERROR_NO_MORE_FILES;
669 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
670 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
674 struct if_msghdr *ifm;
675 struct sockaddr_dl *sdl;
678 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
682 if (!name || !len || !addr || !type)
683 return ERROR_INVALID_PARAMETER;
685 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
686 return ERROR_NO_MORE_FILES;
688 buf = (u_char *)malloc(mibLen);
690 return ERROR_NOT_ENOUGH_MEMORY;
692 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
694 return ERROR_NO_MORE_FILES;
697 ret = ERROR_INVALID_DATA;
698 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
699 ifm = (struct if_msghdr *)p;
700 sdl = (struct sockaddr_dl *)(ifm + 1);
702 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
705 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
706 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
710 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
711 if (addrLen > *len) {
712 ret = ERROR_INSUFFICIENT_BUFFER;
717 memcpy(addr, LLADDR(sdl), addrLen);
718 /* zero out remaining bytes for broken implementations */
719 memset(addr + addrLen, 0, *len - addrLen);
721 #if defined(HAVE_NET_IF_TYPES_H)
722 switch (sdl->sdl_type)
725 *type = MIB_IF_TYPE_ETHERNET;
728 *type = MIB_IF_TYPE_FDDI;
730 case IFT_ISO88024: /* Token Bus */
731 *type = MIB_IF_TYPE_TOKENRING;
733 case IFT_ISO88025: /* Token Ring */
734 *type = MIB_IF_TYPE_TOKENRING;
737 *type = MIB_IF_TYPE_PPP;
740 *type = MIB_IF_TYPE_SLIP;
743 *type = MIB_IF_TYPE_LOOPBACK;
746 *type = MIB_IF_TYPE_OTHER;
749 /* default if we don't know */
750 *type = MIB_IF_TYPE_ETHERNET;
760 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
763 const char *name = getInterfaceNameByIndex(index);
766 return getInterfacePhysicalByName(name, len, addr, type);
768 return ERROR_INVALID_DATA;
771 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
777 return ERROR_INVALID_PARAMETER;
779 return ERROR_INVALID_PARAMETER;
781 fd = socket(PF_INET, SOCK_DGRAM, 0);
785 strncpy(ifr.ifr_name, name, IFNAMSIZ);
786 ifr.ifr_name[IFNAMSIZ-1] = '\0';
787 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
788 ret = ERROR_INVALID_DATA;
795 ret = ERROR_NO_MORE_FILES;
799 DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu)
801 const char *name = getInterfaceNameByIndex(index);
804 return getInterfaceMtuByName(name, mtu);
806 return ERROR_INVALID_DATA;
809 DWORD getInterfaceStatusByName(const char *name, PDWORD status)
815 return ERROR_INVALID_PARAMETER;
817 return ERROR_INVALID_PARAMETER;
819 fd = socket(PF_INET, SOCK_DGRAM, 0);
823 strncpy(ifr.ifr_name, name, IFNAMSIZ);
824 ifr.ifr_name[IFNAMSIZ-1] = '\0';
825 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
826 ret = ERROR_INVALID_DATA;
828 if (ifr.ifr_flags & IFF_UP)
829 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
831 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
836 ret = ERROR_NO_MORE_FILES;
840 DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status)
842 const char *name = getInterfaceNameByIndex(index);
845 return getInterfaceStatusByName(name, status);
847 return ERROR_INVALID_DATA;
850 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
852 BYTE addr[MAX_INTERFACE_PHYSADDR];
853 DWORD ret, len = sizeof(addr), type;
856 return ERROR_INVALID_PARAMETER;
858 return ERROR_INVALID_PARAMETER;
860 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
864 memset(entry, 0, sizeof(MIB_IFROW));
865 for (assigner = entry->wszName, walker = name; *walker;
866 walker++, assigner++)
869 getInterfaceIndexByName(name, &entry->dwIndex);
870 entry->dwPhysAddrLen = len;
871 memcpy(entry->bPhysAddr, addr, len);
872 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
873 entry->dwType = type;
874 /* FIXME: how to calculate real speed? */
875 getInterfaceMtuByName(name, &entry->dwMtu);
876 /* lie, there's no "administratively down" here */
877 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
878 getInterfaceStatusByName(name, &entry->dwOperStatus);
879 /* punt on dwLastChange? */
880 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
881 memcpy(entry->bDescr, name, entry->dwDescrLen);
882 entry->bDescr[entry->dwDescrLen] = '\0';
887 ret = ERROR_INVALID_DATA;
891 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
893 const char *name = getInterfaceNameByIndex(index);
896 return getInterfaceEntryByName(name, entry);
898 return ERROR_INVALID_DATA;
901 char *toIPAddressString(unsigned int addr, char string[16])
904 struct in_addr iAddr;
907 /* extra-anal, just to make auditors happy */
908 strncpy(string, inet_ntoa(iAddr), 16);