wbemdisp: Added WinMGMTS object stub implementation.
[wine/wine-gecko.git] / dlls / iphlpapi / ifenum.c
blobd8eebca860d6ff1eee39007c1c608c86a39d00b9
1 /* Copyright (C) 2003,2006,2011 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 #include "config.h"
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_PARAM_H
31 #include <sys/param.h>
32 #endif
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
44 #endif
46 #ifdef HAVE_NET_IF_H
47 #include <net/if.h>
48 #endif
50 #ifdef HAVE_NET_IF_ARP_H
51 #include <net/if_arp.h>
52 #endif
54 #ifdef HAVE_NET_ROUTE_H
55 #include <net/route.h>
56 #endif
58 #ifdef HAVE_SYS_IOCTL_H
59 #include <sys/ioctl.h>
60 #endif
62 #ifdef HAVE_SYS_SYSCTL_H
63 #include <sys/sysctl.h>
64 #endif
66 #ifdef HAVE_SYS_SOCKIO_H
67 #include <sys/sockio.h>
68 #endif
70 #ifdef HAVE_NET_IF_DL_H
71 #include <net/if_dl.h>
72 #endif
74 #ifdef HAVE_NET_IF_TYPES_H
75 #include <net/if_types.h>
76 #endif
78 #ifdef HAVE_IFADDRS_H
79 #include <ifaddrs.h>
80 #endif
82 #include "ifenum.h"
83 #include "ws2ipdef.h"
85 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
86 #define ifreq_len(ifr) \
87 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
88 #else
89 #define ifreq_len(ifr) sizeof(struct ifreq)
90 #endif
92 #ifndef ETH_ALEN
93 #define ETH_ALEN 6
94 #endif
96 #ifndef IF_NAMESIZE
97 #define IF_NAMESIZE 16
98 #endif
100 #ifndef INADDR_NONE
101 #define INADDR_NONE (~0U)
102 #endif
104 #define INITIAL_INTERFACES_ASSUMED 4
106 /* Functions */
108 static int isLoopbackInterface(int fd, const char *name)
110 int ret = 0;
112 if (name) {
113 struct ifreq ifr;
115 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
116 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
117 ret = ifr.ifr_flags & IFF_LOOPBACK;
119 return ret;
122 /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
123 * bytes are necessary.
125 char *getInterfaceNameByIndex(IF_INDEX index, char *name)
127 return if_indextoname(index, name);
130 DWORD getInterfaceIndexByName(const char *name, IF_INDEX *index)
132 DWORD ret;
133 unsigned int idx;
135 if (!name)
136 return ERROR_INVALID_PARAMETER;
137 if (!index)
138 return ERROR_INVALID_PARAMETER;
139 idx = if_nametoindex(name);
140 if (idx) {
141 *index = idx;
142 ret = NO_ERROR;
144 else
145 ret = ERROR_INVALID_DATA;
146 return ret;
149 BOOL isIfIndexLoopback(ULONG idx)
151 BOOL ret = FALSE;
152 char name[IFNAMSIZ];
153 int fd;
155 getInterfaceNameByIndex(idx, name);
156 fd = socket(PF_INET, SOCK_DGRAM, 0);
157 if (fd != -1) {
158 ret = isLoopbackInterface(fd, name);
159 close(fd);
161 return ret;
164 DWORD getNumNonLoopbackInterfaces(void)
166 DWORD numInterfaces;
167 int fd = socket(PF_INET, SOCK_DGRAM, 0);
169 if (fd != -1) {
170 struct if_nameindex *indexes = if_nameindex();
172 if (indexes) {
173 struct if_nameindex *p;
175 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
176 if (!isLoopbackInterface(fd, p->if_name))
177 numInterfaces++;
178 if_freenameindex(indexes);
180 else
181 numInterfaces = 0;
182 close(fd);
184 else
185 numInterfaces = 0;
186 return numInterfaces;
189 DWORD getNumInterfaces(void)
191 DWORD numInterfaces;
192 struct if_nameindex *indexes = if_nameindex();
194 if (indexes) {
195 struct if_nameindex *p;
197 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
198 numInterfaces++;
199 if_freenameindex(indexes);
201 else
202 numInterfaces = 0;
203 return numInterfaces;
206 InterfaceIndexTable *getInterfaceIndexTable(void)
208 DWORD numInterfaces;
209 InterfaceIndexTable *ret;
210 struct if_nameindex *indexes = if_nameindex();
212 if (indexes) {
213 struct if_nameindex *p;
215 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
216 numInterfaces++;
217 ret = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable, indexes[numInterfaces]));
218 if (ret) {
219 ret->numIndexes = 0;
220 for (p = indexes; p && p->if_name; p++)
221 ret->indexes[ret->numIndexes++] = p->if_index;
223 if_freenameindex(indexes);
225 else
226 ret = NULL;
227 return ret;
230 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
232 DWORD numInterfaces;
233 InterfaceIndexTable *ret;
234 int fd = socket(PF_INET, SOCK_DGRAM, 0);
236 if (fd != -1) {
237 struct if_nameindex *indexes = if_nameindex();
239 if (indexes) {
240 struct if_nameindex *p;
242 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
243 if (!isLoopbackInterface(fd, p->if_name))
244 numInterfaces++;
245 ret = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable, indexes[numInterfaces]));
246 if (ret) {
247 ret->numIndexes = 0;
248 for (p = indexes; p && p->if_name; p++)
249 if (!isLoopbackInterface(fd, p->if_name))
250 ret->indexes[ret->numIndexes++] = p->if_index;
252 if_freenameindex(indexes);
254 else
255 ret = NULL;
256 close(fd);
258 else
259 ret = NULL;
260 return ret;
263 static DWORD getInterfaceBCastAddrByName(const char *name)
265 DWORD ret = INADDR_ANY;
267 if (name) {
268 int fd = socket(PF_INET, SOCK_DGRAM, 0);
270 if (fd != -1) {
271 struct ifreq ifr;
273 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
274 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
275 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
276 close(fd);
279 return ret;
282 static DWORD getInterfaceMaskByName(const char *name)
284 DWORD ret = INADDR_NONE;
286 if (name) {
287 int fd = socket(PF_INET, SOCK_DGRAM, 0);
289 if (fd != -1) {
290 struct ifreq ifr;
292 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
293 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
294 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
295 close(fd);
298 return ret;
301 #if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
302 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
303 PDWORD type)
305 DWORD ret;
306 int fd;
308 if (!name || !len || !addr || !type)
309 return ERROR_INVALID_PARAMETER;
311 fd = socket(PF_INET, SOCK_DGRAM, 0);
312 if (fd != -1) {
313 struct ifreq ifr;
315 memset(&ifr, 0, sizeof(struct ifreq));
316 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
317 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
318 ret = ERROR_INVALID_DATA;
319 else {
320 unsigned int addrLen;
322 switch (ifr.ifr_hwaddr.sa_family)
324 #ifdef ARPHRD_LOOPBACK
325 case ARPHRD_LOOPBACK:
326 addrLen = 0;
327 *type = MIB_IF_TYPE_LOOPBACK;
328 break;
329 #endif
330 #ifdef ARPHRD_ETHER
331 case ARPHRD_ETHER:
332 addrLen = ETH_ALEN;
333 *type = MIB_IF_TYPE_ETHERNET;
334 break;
335 #endif
336 #ifdef ARPHRD_FDDI
337 case ARPHRD_FDDI:
338 addrLen = ETH_ALEN;
339 *type = MIB_IF_TYPE_FDDI;
340 break;
341 #endif
342 #ifdef ARPHRD_IEEE802
343 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
344 addrLen = ETH_ALEN;
345 *type = MIB_IF_TYPE_TOKENRING;
346 break;
347 #endif
348 #ifdef ARPHRD_IEEE802_TR
349 case ARPHRD_IEEE802_TR: /* also Token Ring? */
350 addrLen = ETH_ALEN;
351 *type = MIB_IF_TYPE_TOKENRING;
352 break;
353 #endif
354 #ifdef ARPHRD_SLIP
355 case ARPHRD_SLIP:
356 addrLen = 0;
357 *type = MIB_IF_TYPE_SLIP;
358 break;
359 #endif
360 #ifdef ARPHRD_PPP
361 case ARPHRD_PPP:
362 addrLen = 0;
363 *type = MIB_IF_TYPE_PPP;
364 break;
365 #endif
366 default:
367 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
368 *type = MIB_IF_TYPE_OTHER;
370 if (addrLen > *len) {
371 ret = ERROR_INSUFFICIENT_BUFFER;
372 *len = addrLen;
374 else {
375 if (addrLen > 0)
376 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
377 /* zero out remaining bytes for broken implementations */
378 memset(addr + addrLen, 0, *len - addrLen);
379 *len = addrLen;
380 ret = NO_ERROR;
383 close(fd);
385 else
386 ret = ERROR_NO_MORE_FILES;
387 return ret;
389 #elif defined (SIOCGARP)
390 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
391 PDWORD type)
393 DWORD ret;
394 int fd;
396 if (!name || !len || !addr || !type)
397 return ERROR_INVALID_PARAMETER;
399 fd = socket(PF_INET, SOCK_DGRAM, 0);
400 if (fd != -1) {
401 if (isLoopbackInterface(fd, name)) {
402 *type = MIB_IF_TYPE_LOOPBACK;
403 memset(addr, 0, *len);
404 *len = 0;
405 ret=NOERROR;
407 else {
408 struct arpreq arp;
409 struct sockaddr_in *saddr;
410 struct ifreq ifr;
412 /* get IP addr */
413 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
414 ioctl(fd, SIOCGIFADDR, &ifr);
415 memset(&arp, 0, sizeof(struct arpreq));
416 arp.arp_pa.sa_family = AF_INET;
417 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
418 saddr->sin_family = AF_INET;
419 memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
420 if ((ioctl(fd, SIOCGARP, &arp)))
421 ret = ERROR_INVALID_DATA;
422 else {
423 /* FIXME: heh: who said it was ethernet? */
424 int addrLen = ETH_ALEN;
426 if (addrLen > *len) {
427 ret = ERROR_INSUFFICIENT_BUFFER;
428 *len = addrLen;
430 else {
431 if (addrLen > 0)
432 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
433 /* zero out remaining bytes for broken implementations */
434 memset(addr + addrLen, 0, *len - addrLen);
435 *len = addrLen;
436 *type = MIB_IF_TYPE_ETHERNET;
437 ret = NO_ERROR;
441 close(fd);
443 else
444 ret = ERROR_NO_MORE_FILES;
446 return ret;
448 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
449 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
450 PDWORD type)
452 DWORD ret;
453 struct if_msghdr *ifm;
454 struct sockaddr_dl *sdl;
455 u_char *p, *buf;
456 size_t mibLen;
457 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
458 unsigned addrLen;
459 BOOL found = FALSE;
461 if (!name || !len || !addr || !type)
462 return ERROR_INVALID_PARAMETER;
464 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
465 return ERROR_NO_MORE_FILES;
467 buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
468 if (!buf)
469 return ERROR_NOT_ENOUGH_MEMORY;
471 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
472 HeapFree(GetProcessHeap(), 0, buf);
473 return ERROR_NO_MORE_FILES;
476 ret = ERROR_INVALID_DATA;
477 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
478 ifm = (struct if_msghdr *)p;
479 sdl = (struct sockaddr_dl *)(ifm + 1);
481 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
482 continue;
484 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
485 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
486 continue;
488 found = TRUE;
489 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
490 if (addrLen > *len) {
491 ret = ERROR_INSUFFICIENT_BUFFER;
492 *len = addrLen;
494 else {
495 if (addrLen > 0)
496 memcpy(addr, LLADDR(sdl), addrLen);
497 /* zero out remaining bytes for broken implementations */
498 memset(addr + addrLen, 0, *len - addrLen);
499 *len = addrLen;
500 #if defined(HAVE_NET_IF_TYPES_H)
501 switch (sdl->sdl_type)
503 case IFT_ETHER:
504 *type = MIB_IF_TYPE_ETHERNET;
505 break;
506 case IFT_FDDI:
507 *type = MIB_IF_TYPE_FDDI;
508 break;
509 case IFT_ISO88024: /* Token Bus */
510 *type = MIB_IF_TYPE_TOKENRING;
511 break;
512 case IFT_ISO88025: /* Token Ring */
513 *type = MIB_IF_TYPE_TOKENRING;
514 break;
515 case IFT_PPP:
516 *type = MIB_IF_TYPE_PPP;
517 break;
518 case IFT_SLIP:
519 *type = MIB_IF_TYPE_SLIP;
520 break;
521 case IFT_LOOP:
522 *type = MIB_IF_TYPE_LOOPBACK;
523 break;
524 default:
525 *type = MIB_IF_TYPE_OTHER;
527 #else
528 /* default if we don't know */
529 *type = MIB_IF_TYPE_ETHERNET;
530 #endif
531 ret = NO_ERROR;
534 HeapFree(GetProcessHeap(), 0, buf);
535 return ret;
537 #endif
539 DWORD getInterfacePhysicalByIndex(IF_INDEX index, PDWORD len, PBYTE addr,
540 PDWORD type)
542 char nameBuf[IF_NAMESIZE];
543 char *name = getInterfaceNameByIndex(index, nameBuf);
545 if (name)
546 return getInterfacePhysicalByName(name, len, addr, type);
547 else
548 return ERROR_INVALID_DATA;
551 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
553 DWORD ret;
554 int fd;
556 if (!name)
557 return ERROR_INVALID_PARAMETER;
558 if (!mtu)
559 return ERROR_INVALID_PARAMETER;
561 fd = socket(PF_INET, SOCK_DGRAM, 0);
562 if (fd != -1) {
563 struct ifreq ifr;
565 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
566 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
567 ret = ERROR_INVALID_DATA;
568 else {
569 #ifndef __sun
570 *mtu = ifr.ifr_mtu;
571 #else
572 *mtu = ifr.ifr_metric;
573 #endif
574 ret = NO_ERROR;
576 close(fd);
578 else
579 ret = ERROR_NO_MORE_FILES;
580 return ret;
583 DWORD getInterfaceStatusByName(const char *name, INTERNAL_IF_OPER_STATUS *status)
585 DWORD ret;
586 int fd;
588 if (!name)
589 return ERROR_INVALID_PARAMETER;
590 if (!status)
591 return ERROR_INVALID_PARAMETER;
593 fd = socket(PF_INET, SOCK_DGRAM, 0);
594 if (fd != -1) {
595 struct ifreq ifr;
597 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
598 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
599 ret = ERROR_INVALID_DATA;
600 else {
601 if (ifr.ifr_flags & IFF_UP)
602 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
603 else
604 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
605 ret = NO_ERROR;
607 close(fd);
609 else
610 ret = ERROR_NO_MORE_FILES;
611 return ret;
614 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
616 BYTE addr[MAX_INTERFACE_PHYSADDR];
617 DWORD ret, len = sizeof(addr), type;
619 if (!name)
620 return ERROR_INVALID_PARAMETER;
621 if (!entry)
622 return ERROR_INVALID_PARAMETER;
624 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
625 WCHAR *assigner;
626 const char *walker;
628 memset(entry, 0, sizeof(MIB_IFROW));
629 for (assigner = entry->wszName, walker = name; *walker;
630 walker++, assigner++)
631 *assigner = *walker;
632 *assigner = 0;
633 getInterfaceIndexByName(name, &entry->dwIndex);
634 entry->dwPhysAddrLen = len;
635 memcpy(entry->bPhysAddr, addr, len);
636 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
637 entry->dwType = type;
638 /* FIXME: how to calculate real speed? */
639 getInterfaceMtuByName(name, &entry->dwMtu);
640 /* lie, there's no "administratively down" here */
641 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
642 getInterfaceStatusByName(name, &entry->dwOperStatus);
643 /* punt on dwLastChange? */
644 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
645 memcpy(entry->bDescr, name, entry->dwDescrLen);
646 entry->bDescr[entry->dwDescrLen] = '\0';
647 entry->dwDescrLen++;
648 ret = NO_ERROR;
650 else
651 ret = ERROR_INVALID_DATA;
652 return ret;
655 static DWORD getIPAddrRowByName(PMIB_IPADDRROW ipAddrRow, const char *ifName,
656 const struct sockaddr *sa)
658 DWORD ret, bcast;
660 ret = getInterfaceIndexByName(ifName, &ipAddrRow->dwIndex);
661 memcpy(&ipAddrRow->dwAddr, sa->sa_data + 2, sizeof(DWORD));
662 ipAddrRow->dwMask = getInterfaceMaskByName(ifName);
663 /* the dwBCastAddr member isn't the broadcast address, it indicates whether
664 * the interface uses the 1's broadcast address (1) or the 0's broadcast
665 * address (0).
667 bcast = getInterfaceBCastAddrByName(ifName);
668 ipAddrRow->dwBCastAddr = (bcast & ipAddrRow->dwMask) ? 1 : 0;
669 /* FIXME: hardcoded reasm size, not sure where to get it */
670 ipAddrRow->dwReasmSize = 65535;
671 ipAddrRow->unused1 = 0;
672 ipAddrRow->wType = 0;
673 return ret;
676 #ifdef HAVE_IFADDRS_H
678 /* Counts the IPv4 addresses in the system using the return value from
679 * getifaddrs, returning the count.
681 static DWORD countIPv4Addresses(struct ifaddrs *ifa)
683 DWORD numAddresses = 0;
685 for (; ifa; ifa = ifa->ifa_next)
686 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET)
687 numAddresses++;
688 return numAddresses;
691 DWORD getNumIPAddresses(void)
693 DWORD numAddresses = 0;
694 struct ifaddrs *ifa;
696 if (!getifaddrs(&ifa))
698 numAddresses = countIPv4Addresses(ifa);
699 freeifaddrs(ifa);
701 return numAddresses;
704 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
706 DWORD ret;
708 if (!ppIpAddrTable)
709 ret = ERROR_INVALID_PARAMETER;
710 else
712 struct ifaddrs *ifa;
714 if (!getifaddrs(&ifa))
716 DWORD size = sizeof(MIB_IPADDRTABLE);
717 DWORD numAddresses = countIPv4Addresses(ifa);
719 if (numAddresses > 1)
720 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
721 *ppIpAddrTable = HeapAlloc(heap, flags, size);
722 if (*ppIpAddrTable)
724 DWORD i = 0;
725 struct ifaddrs *ifp;
727 ret = NO_ERROR;
728 (*ppIpAddrTable)->dwNumEntries = numAddresses;
729 for (ifp = ifa; !ret && ifp; ifp = ifp->ifa_next)
731 if (!ifp->ifa_addr || ifp->ifa_addr->sa_family != AF_INET)
732 continue;
734 ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifp->ifa_name,
735 ifp->ifa_addr);
736 i++;
738 if (ret)
739 HeapFree(GetProcessHeap(), 0, *ppIpAddrTable);
741 else
742 ret = ERROR_OUTOFMEMORY;
743 freeifaddrs(ifa);
745 else
746 ret = ERROR_INVALID_PARAMETER;
748 return ret;
751 ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
753 struct ifaddrs *ifa;
754 ULONG ret;
756 if (!getifaddrs(&ifa))
758 struct ifaddrs *p;
759 ULONG n;
760 char name[IFNAMSIZ];
762 getInterfaceNameByIndex(index, name);
763 for (p = ifa, n = 0; p; p = p->ifa_next)
764 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
765 !strcmp(name, p->ifa_name))
766 n++;
767 if (n)
769 *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
770 sizeof(struct WS_sockaddr_in6)));
771 if (*addrs)
773 struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
774 (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
776 for (p = ifa, n = 0; p; p = p->ifa_next)
778 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
779 !strcmp(name, p->ifa_name))
781 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
783 next_addr->sin6_family = WS_AF_INET6;
784 next_addr->sin6_port = addr->sin6_port;
785 next_addr->sin6_flowinfo = addr->sin6_flowinfo;
786 memcpy(&next_addr->sin6_addr, &addr->sin6_addr,
787 sizeof(next_addr->sin6_addr));
788 next_addr->sin6_scope_id = addr->sin6_scope_id;
789 (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
790 (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
791 next_addr++;
792 n++;
795 *num_addrs = n;
796 ret = ERROR_SUCCESS;
798 else
799 ret = ERROR_OUTOFMEMORY;
801 else
803 *addrs = NULL;
804 *num_addrs = 0;
805 ret = ERROR_SUCCESS;
807 freeifaddrs(ifa);
809 else
810 ret = ERROR_NO_DATA;
811 return ret;
814 #else
816 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
817 * the count to you in *pcAddresses. It also returns to you the struct ifconf
818 * used by the call to ioctl, so that you may process the addresses further.
819 * Free ifc->ifc_buf using HeapFree.
820 * Returns NO_ERROR on success, something else on failure.
822 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
824 DWORD ret;
825 int fd;
827 fd = socket(PF_INET, SOCK_DGRAM, 0);
828 if (fd != -1) {
829 int ioctlRet = 0;
830 DWORD guessedNumAddresses = 0, numAddresses = 0;
831 caddr_t ifPtr;
832 int lastlen;
834 ret = NO_ERROR;
835 ifc->ifc_len = 0;
836 ifc->ifc_buf = NULL;
837 /* there is no way to know the interface count beforehand,
838 so we need to loop again and again upping our max each time
839 until returned is constant across 2 calls */
840 do {
841 lastlen = ifc->ifc_len;
842 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
843 if (guessedNumAddresses == 0)
844 guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
845 else
846 guessedNumAddresses *= 2;
847 ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
848 ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
849 ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
850 } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
852 if (ioctlRet == 0) {
853 ifPtr = ifc->ifc_buf;
854 while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
855 struct ifreq *ifr = (struct ifreq *)ifPtr;
857 if (ifr->ifr_addr.sa_family == AF_INET)
858 numAddresses++;
860 ifPtr += ifreq_len((struct ifreq *)ifPtr);
863 else
864 ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
865 if (!ret)
866 *pcAddresses = numAddresses;
867 else
869 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
870 ifc->ifc_buf = NULL;
872 close(fd);
874 else
875 ret = ERROR_NO_SYSTEM_RESOURCES;
876 return ret;
879 DWORD getNumIPAddresses(void)
881 DWORD numAddresses = 0;
882 struct ifconf ifc;
884 if (!enumIPAddresses(&numAddresses, &ifc))
885 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
886 return numAddresses;
889 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
891 DWORD ret;
893 if (!ppIpAddrTable)
894 ret = ERROR_INVALID_PARAMETER;
895 else
897 DWORD numAddresses = 0;
898 struct ifconf ifc;
900 ret = enumIPAddresses(&numAddresses, &ifc);
901 if (!ret)
903 DWORD size = sizeof(MIB_IPADDRTABLE);
905 if (numAddresses > 1)
906 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
907 *ppIpAddrTable = HeapAlloc(heap, flags, size);
908 if (*ppIpAddrTable) {
909 DWORD i = 0;
910 caddr_t ifPtr;
912 ret = NO_ERROR;
913 (*ppIpAddrTable)->dwNumEntries = numAddresses;
914 ifPtr = ifc.ifc_buf;
915 while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
916 struct ifreq *ifr = (struct ifreq *)ifPtr;
918 ifPtr += ifreq_len(ifr);
920 if (ifr->ifr_addr.sa_family != AF_INET)
921 continue;
923 ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifr->ifr_name,
924 &ifr->ifr_addr);
925 i++;
927 if (ret)
928 HeapFree(GetProcessHeap(), 0, *ppIpAddrTable);
930 else
931 ret = ERROR_OUTOFMEMORY;
932 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
935 return ret;
938 ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
940 *addrs = NULL;
941 *num_addrs = 0;
942 return ERROR_SUCCESS;
945 #endif
947 char *toIPAddressString(unsigned int addr, char string[16])
949 if (string) {
950 struct in_addr iAddr;
952 iAddr.s_addr = addr;
953 /* extra-anal, just to make auditors happy */
954 lstrcpynA(string, inet_ntoa(iAddr), 16);
956 return string;