1 /* Copyright (C) 2003,2006 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 implemented 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 static DWORD getInterfaceBCastAddrByName(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, SIOCGIFBRDADDR, &ifr) == 0)
470 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
477 static DWORD getInterfaceMaskByName(const char *name)
479 DWORD ret = INADDR_NONE;
482 int fd = socket(PF_INET, SOCK_DGRAM, 0);
487 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
488 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
489 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
496 #if defined (SIOCGIFHWADDR)
497 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
503 if (!name || !len || !addr || !type)
504 return ERROR_INVALID_PARAMETER;
506 fd = socket(PF_INET, SOCK_DGRAM, 0);
510 memset(&ifr, 0, sizeof(struct ifreq));
511 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
512 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
513 ret = ERROR_INVALID_DATA;
515 unsigned int addrLen;
517 switch (ifr.ifr_hwaddr.sa_family)
519 #ifdef ARPHRD_LOOPBACK
520 case ARPHRD_LOOPBACK:
522 *type = MIB_IF_TYPE_LOOPBACK;
528 *type = MIB_IF_TYPE_ETHERNET;
534 *type = MIB_IF_TYPE_FDDI;
537 #ifdef ARPHRD_IEEE802
538 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
540 *type = MIB_IF_TYPE_TOKENRING;
543 #ifdef ARPHRD_IEEE802_TR
544 case ARPHRD_IEEE802_TR: /* also Token Ring? */
546 *type = MIB_IF_TYPE_TOKENRING;
552 *type = MIB_IF_TYPE_SLIP;
558 *type = MIB_IF_TYPE_PPP;
562 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
563 *type = MIB_IF_TYPE_OTHER;
565 if (addrLen > *len) {
566 ret = ERROR_INSUFFICIENT_BUFFER;
571 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
572 /* zero out remaining bytes for broken implementations */
573 memset(addr + addrLen, 0, *len - addrLen);
581 ret = ERROR_NO_MORE_FILES;
584 #elif defined (SIOCGARP)
585 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
591 if (!name || !len || !addr || !type)
592 return ERROR_INVALID_PARAMETER;
594 fd = socket(PF_INET, SOCK_DGRAM, 0);
596 if (isLoopbackInterface(fd, name)) {
597 *type = MIB_IF_TYPE_LOOPBACK;
598 memset(addr, 0, *len);
604 struct sockaddr_in *saddr;
608 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
609 ioctl(fd, SIOCGIFADDR, &ifr);
610 memset(&arp, 0, sizeof(struct arpreq));
611 arp.arp_pa.sa_family = AF_INET;
612 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
613 saddr->sin_family = AF_INET;
614 memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
615 if ((ioctl(fd, SIOCGARP, &arp)))
616 ret = ERROR_INVALID_DATA;
618 /* FIXME: heh: who said it was ethernet? */
619 int addrLen = ETH_ALEN;
621 if (addrLen > *len) {
622 ret = ERROR_INSUFFICIENT_BUFFER;
627 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
628 /* zero out remaining bytes for broken implementations */
629 memset(addr + addrLen, 0, *len - addrLen);
631 *type = MIB_IF_TYPE_ETHERNET;
639 ret = ERROR_NO_MORE_FILES;
643 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
644 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
648 struct if_msghdr *ifm;
649 struct sockaddr_dl *sdl;
652 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
656 if (!name || !len || !addr || !type)
657 return ERROR_INVALID_PARAMETER;
659 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
660 return ERROR_NO_MORE_FILES;
662 buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
664 return ERROR_NOT_ENOUGH_MEMORY;
666 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
667 HeapFree(GetProcessHeap(), 0, buf);
668 return ERROR_NO_MORE_FILES;
671 ret = ERROR_INVALID_DATA;
672 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
673 ifm = (struct if_msghdr *)p;
674 sdl = (struct sockaddr_dl *)(ifm + 1);
676 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
679 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
680 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
684 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
685 if (addrLen > *len) {
686 ret = ERROR_INSUFFICIENT_BUFFER;
691 memcpy(addr, LLADDR(sdl), addrLen);
692 /* zero out remaining bytes for broken implementations */
693 memset(addr + addrLen, 0, *len - addrLen);
695 #if defined(HAVE_NET_IF_TYPES_H)
696 switch (sdl->sdl_type)
699 *type = MIB_IF_TYPE_ETHERNET;
702 *type = MIB_IF_TYPE_FDDI;
704 case IFT_ISO88024: /* Token Bus */
705 *type = MIB_IF_TYPE_TOKENRING;
707 case IFT_ISO88025: /* Token Ring */
708 *type = MIB_IF_TYPE_TOKENRING;
711 *type = MIB_IF_TYPE_PPP;
714 *type = MIB_IF_TYPE_SLIP;
717 *type = MIB_IF_TYPE_LOOPBACK;
720 *type = MIB_IF_TYPE_OTHER;
723 /* default if we don't know */
724 *type = MIB_IF_TYPE_ETHERNET;
729 HeapFree(GetProcessHeap(), 0, buf);
734 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
737 const char *name = getInterfaceNameByIndex(index);
740 return getInterfacePhysicalByName(name, len, addr, type);
742 return ERROR_INVALID_DATA;
745 static DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
751 return ERROR_INVALID_PARAMETER;
753 return ERROR_INVALID_PARAMETER;
755 fd = socket(PF_INET, SOCK_DGRAM, 0);
759 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
760 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
761 ret = ERROR_INVALID_DATA;
766 *mtu = ifr.ifr_metric;
773 ret = ERROR_NO_MORE_FILES;
777 static DWORD getInterfaceStatusByName(const char *name, PDWORD status)
783 return ERROR_INVALID_PARAMETER;
785 return ERROR_INVALID_PARAMETER;
787 fd = socket(PF_INET, SOCK_DGRAM, 0);
791 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
792 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
793 ret = ERROR_INVALID_DATA;
795 if (ifr.ifr_flags & IFF_UP)
796 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
798 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
804 ret = ERROR_NO_MORE_FILES;
808 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
810 BYTE addr[MAX_INTERFACE_PHYSADDR];
811 DWORD ret, len = sizeof(addr), type;
814 return ERROR_INVALID_PARAMETER;
816 return ERROR_INVALID_PARAMETER;
818 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
822 memset(entry, 0, sizeof(MIB_IFROW));
823 for (assigner = entry->wszName, walker = name; *walker;
824 walker++, assigner++)
827 getInterfaceIndexByName(name, &entry->dwIndex);
828 entry->dwPhysAddrLen = len;
829 memcpy(entry->bPhysAddr, addr, len);
830 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
831 entry->dwType = type;
832 /* FIXME: how to calculate real speed? */
833 getInterfaceMtuByName(name, &entry->dwMtu);
834 /* lie, there's no "administratively down" here */
835 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
836 getInterfaceStatusByName(name, &entry->dwOperStatus);
837 /* punt on dwLastChange? */
838 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
839 memcpy(entry->bDescr, name, entry->dwDescrLen);
840 entry->bDescr[entry->dwDescrLen] = '\0';
845 ret = ERROR_INVALID_DATA;
849 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
851 const char *name = getInterfaceNameByIndex(index);
854 return getInterfaceEntryByName(name, entry);
856 return ERROR_INVALID_DATA;
859 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
860 * the count to you in *pcAddresses. It also returns to you the struct ifconf
861 * used by the call to ioctl, so that you may process the addresses further.
862 * Free ifc->ifc_buf using HeapFree.
863 * Returns NO_ERROR on success, something else on failure.
865 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
870 fd = socket(PF_INET, SOCK_DGRAM, 0);
873 DWORD guessedNumAddresses = 0, numAddresses = 0;
879 /* there is no way to know the interface count beforehand,
880 so we need to loop again and again upping our max each time
881 until returned < max */
883 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
884 if (guessedNumAddresses == 0)
885 guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
887 guessedNumAddresses *= 2;
888 ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
889 ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
890 ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
891 } while (ioctlRet == 0 &&
892 ifc->ifc_len == (sizeof(struct ifreq) * guessedNumAddresses));
895 ifPtr = ifc->ifc_buf;
896 while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
898 ifPtr += ifreq_len((struct ifreq *)ifPtr);
902 ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
904 *pcAddresses = numAddresses;
907 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
913 ret = ERROR_NO_SYSTEM_RESOURCES;
917 DWORD getNumIPAddresses(void)
919 DWORD numAddresses = 0;
922 if (!enumIPAddresses(&numAddresses, &ifc))
923 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
927 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
932 ret = ERROR_INVALID_PARAMETER;
935 DWORD numAddresses = 0;
938 ret = enumIPAddresses(&numAddresses, &ifc);
941 *ppIpAddrTable = HeapAlloc(heap, flags, sizeof(MIB_IPADDRTABLE) +
942 (numAddresses - 1) * sizeof(MIB_IPADDRROW));
943 if (*ppIpAddrTable) {
948 (*ppIpAddrTable)->dwNumEntries = numAddresses;
950 while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
951 struct ifreq *ifr = (struct ifreq *)ifPtr;
953 ret = getInterfaceIndexByName(ifr->ifr_name,
954 &(*ppIpAddrTable)->table[i].dwIndex);
955 memcpy(&(*ppIpAddrTable)->table[i].dwAddr, ifr->ifr_addr.sa_data + 2,
957 (*ppIpAddrTable)->table[i].dwMask =
958 getInterfaceMaskByName(ifr->ifr_name);
959 /* the dwBCastAddr member isn't the broadcast address, it indicates
960 * whether the interface uses the 1's broadcast address (1) or the
961 * 0's broadcast address (0).
963 bcast = getInterfaceBCastAddrByName(ifr->ifr_name);
964 (*ppIpAddrTable)->table[i].dwBCastAddr =
965 (bcast & (*ppIpAddrTable)->table[i].dwMask) ? 1 : 0;
966 /* FIXME: hardcoded reasm size, not sure where to get it */
967 (*ppIpAddrTable)->table[i].dwReasmSize = 65535;
969 (*ppIpAddrTable)->table[i].unused1 = 0;
970 (*ppIpAddrTable)->table[i].wType = 0;
971 ifPtr += ifreq_len(ifr);
976 ret = ERROR_OUTOFMEMORY;
977 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
983 char *toIPAddressString(unsigned int addr, char string[16])
986 struct in_addr iAddr;
989 /* extra-anal, just to make auditors happy */
990 lstrcpynA(string, inet_ntoa(iAddr), 16);