advapi32: Make rpcrt4 a delayed import to work around circular dependencies with...
[wine/testsucceed.git] / dlls / iphlpapi / ifenum.c
blob4628b2134c792d68c8fb0e92c73c93e963aa80c2
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 * Implementation notes
18 * FIXME:
19 * - I don't support IPv6 addresses here, since SIOCGIFCONF can't return them
21 * There are three implemented methods for determining the MAC address of an
22 * interface:
23 * - a specific IOCTL (Linux)
24 * - looking in the ARP cache (at least Solaris)
25 * - using the sysctl interface (FreeBSD and Mac OS X)
26 * Solaris and some others have SIOCGENADDR, but I haven't gotten that to work
27 * on the Solaris boxes at SourceForge's compile farm, whereas SIOCGARP does.
30 #include "config.h"
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
41 #include <sys/types.h>
42 #ifdef HAVE_SYS_PARAM_H
43 #include <sys/param.h>
44 #endif
46 #ifdef HAVE_SYS_SOCKET_H
47 #include <sys/socket.h>
48 #endif
50 #ifdef HAVE_NETINET_IN_H
51 #include <netinet/in.h>
52 #endif
54 #ifdef HAVE_ARPA_INET_H
55 #include <arpa/inet.h>
56 #endif
58 #ifdef HAVE_NET_IF_H
59 #include <net/if.h>
60 #endif
62 #ifdef HAVE_NET_IF_ARP_H
63 #include <net/if_arp.h>
64 #endif
66 #ifdef HAVE_NET_ROUTE_H
67 #include <net/route.h>
68 #endif
70 #ifdef HAVE_SYS_IOCTL_H
71 #include <sys/ioctl.h>
72 #endif
74 #ifdef HAVE_SYS_SYSCTL_H
75 #include <sys/sysctl.h>
76 #endif
78 #ifdef HAVE_SYS_SOCKIO_H
79 #include <sys/sockio.h>
80 #endif
82 #ifdef HAVE_NET_IF_DL_H
83 #include <net/if_dl.h>
84 #endif
86 #ifdef HAVE_NET_IF_TYPES_H
87 #include <net/if_types.h>
88 #endif
90 #ifdef HAVE_IFADDRS_H
91 #include <ifaddrs.h>
92 #endif
94 #include "ifenum.h"
95 #include "ws2ipdef.h"
97 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
98 #define ifreq_len(ifr) \
99 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
100 #else
101 #define ifreq_len(ifr) sizeof(struct ifreq)
102 #endif
104 #ifndef ETH_ALEN
105 #define ETH_ALEN 6
106 #endif
108 #ifndef IF_NAMESIZE
109 #define IF_NAMESIZE 16
110 #endif
112 #ifndef INADDR_NONE
113 #define INADDR_NONE (~0U)
114 #endif
116 #define INITIAL_INTERFACES_ASSUMED 4
118 /* Functions */
120 static int isLoopbackInterface(int fd, const char *name)
122 int ret = 0;
124 if (name) {
125 struct ifreq ifr;
127 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
128 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
129 ret = ifr.ifr_flags & IFF_LOOPBACK;
131 return ret;
134 /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
135 * bytes are necessary.
137 char *getInterfaceNameByIndex(DWORD index, char *name)
139 return if_indextoname(index, name);
142 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
144 DWORD ret;
145 unsigned int idx;
147 if (!name)
148 return ERROR_INVALID_PARAMETER;
149 if (!index)
150 return ERROR_INVALID_PARAMETER;
151 idx = if_nametoindex(name);
152 if (idx) {
153 *index = idx;
154 ret = NO_ERROR;
156 else
157 ret = ERROR_INVALID_DATA;
158 return ret;
161 DWORD getNumNonLoopbackInterfaces(void)
163 DWORD numInterfaces;
164 int fd = socket(PF_INET, SOCK_DGRAM, 0);
166 if (fd != -1) {
167 struct if_nameindex *indexes = if_nameindex();
169 if (indexes) {
170 struct if_nameindex *p;
172 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
173 if (!isLoopbackInterface(fd, p->if_name))
174 numInterfaces++;
175 if_freenameindex(indexes);
177 else
178 numInterfaces = 0;
179 close(fd);
181 else
182 numInterfaces = 0;
183 return numInterfaces;
186 DWORD getNumInterfaces(void)
188 DWORD numInterfaces;
189 struct if_nameindex *indexes = if_nameindex();
191 if (indexes) {
192 struct if_nameindex *p;
194 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
195 numInterfaces++;
196 if_freenameindex(indexes);
198 else
199 numInterfaces = 0;
200 return numInterfaces;
203 InterfaceIndexTable *getInterfaceIndexTable(void)
205 DWORD numInterfaces;
206 InterfaceIndexTable *ret;
207 struct if_nameindex *indexes = if_nameindex();
209 if (indexes) {
210 struct if_nameindex *p;
211 DWORD size = sizeof(InterfaceIndexTable);
213 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
214 numInterfaces++;
215 if (numInterfaces > 1)
216 size += (numInterfaces - 1) * sizeof(DWORD);
217 ret = HeapAlloc(GetProcessHeap(), 0, size);
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;
241 DWORD size = sizeof(InterfaceIndexTable);
243 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
244 if (!isLoopbackInterface(fd, p->if_name))
245 numInterfaces++;
246 if (numInterfaces > 1)
247 size += (numInterfaces - 1) * sizeof(DWORD);
248 ret = HeapAlloc(GetProcessHeap(), 0, size);
249 if (ret) {
250 ret->numIndexes = 0;
251 for (p = indexes; p && p->if_name; p++)
252 if (!isLoopbackInterface(fd, p->if_name))
253 ret->indexes[ret->numIndexes++] = p->if_index;
255 if_freenameindex(indexes);
257 else
258 ret = NULL;
259 close(fd);
261 else
262 ret = NULL;
263 return ret;
266 static DWORD getInterfaceBCastAddrByName(const char *name)
268 DWORD ret = INADDR_ANY;
270 if (name) {
271 int fd = socket(PF_INET, SOCK_DGRAM, 0);
273 if (fd != -1) {
274 struct ifreq ifr;
276 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
277 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
278 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
279 close(fd);
282 return ret;
285 static DWORD getInterfaceMaskByName(const char *name)
287 DWORD ret = INADDR_NONE;
289 if (name) {
290 int fd = socket(PF_INET, SOCK_DGRAM, 0);
292 if (fd != -1) {
293 struct ifreq ifr;
295 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
296 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
297 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
298 close(fd);
301 return ret;
304 #if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
305 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
306 PDWORD type)
308 DWORD ret;
309 int fd;
311 if (!name || !len || !addr || !type)
312 return ERROR_INVALID_PARAMETER;
314 fd = socket(PF_INET, SOCK_DGRAM, 0);
315 if (fd != -1) {
316 struct ifreq ifr;
318 memset(&ifr, 0, sizeof(struct ifreq));
319 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
320 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
321 ret = ERROR_INVALID_DATA;
322 else {
323 unsigned int addrLen;
325 switch (ifr.ifr_hwaddr.sa_family)
327 #ifdef ARPHRD_LOOPBACK
328 case ARPHRD_LOOPBACK:
329 addrLen = 0;
330 *type = MIB_IF_TYPE_LOOPBACK;
331 break;
332 #endif
333 #ifdef ARPHRD_ETHER
334 case ARPHRD_ETHER:
335 addrLen = ETH_ALEN;
336 *type = MIB_IF_TYPE_ETHERNET;
337 break;
338 #endif
339 #ifdef ARPHRD_FDDI
340 case ARPHRD_FDDI:
341 addrLen = ETH_ALEN;
342 *type = MIB_IF_TYPE_FDDI;
343 break;
344 #endif
345 #ifdef ARPHRD_IEEE802
346 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
347 addrLen = ETH_ALEN;
348 *type = MIB_IF_TYPE_TOKENRING;
349 break;
350 #endif
351 #ifdef ARPHRD_IEEE802_TR
352 case ARPHRD_IEEE802_TR: /* also Token Ring? */
353 addrLen = ETH_ALEN;
354 *type = MIB_IF_TYPE_TOKENRING;
355 break;
356 #endif
357 #ifdef ARPHRD_SLIP
358 case ARPHRD_SLIP:
359 addrLen = 0;
360 *type = MIB_IF_TYPE_SLIP;
361 break;
362 #endif
363 #ifdef ARPHRD_PPP
364 case ARPHRD_PPP:
365 addrLen = 0;
366 *type = MIB_IF_TYPE_PPP;
367 break;
368 #endif
369 default:
370 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
371 *type = MIB_IF_TYPE_OTHER;
373 if (addrLen > *len) {
374 ret = ERROR_INSUFFICIENT_BUFFER;
375 *len = addrLen;
377 else {
378 if (addrLen > 0)
379 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
380 /* zero out remaining bytes for broken implementations */
381 memset(addr + addrLen, 0, *len - addrLen);
382 *len = addrLen;
383 ret = NO_ERROR;
386 close(fd);
388 else
389 ret = ERROR_NO_MORE_FILES;
390 return ret;
392 #elif defined (SIOCGARP)
393 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
394 PDWORD type)
396 DWORD ret;
397 int fd;
399 if (!name || !len || !addr || !type)
400 return ERROR_INVALID_PARAMETER;
402 fd = socket(PF_INET, SOCK_DGRAM, 0);
403 if (fd != -1) {
404 if (isLoopbackInterface(fd, name)) {
405 *type = MIB_IF_TYPE_LOOPBACK;
406 memset(addr, 0, *len);
407 *len = 0;
408 ret=NOERROR;
410 else {
411 struct arpreq arp;
412 struct sockaddr_in *saddr;
413 struct ifreq ifr;
415 /* get IP addr */
416 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
417 ioctl(fd, SIOCGIFADDR, &ifr);
418 memset(&arp, 0, sizeof(struct arpreq));
419 arp.arp_pa.sa_family = AF_INET;
420 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
421 saddr->sin_family = AF_INET;
422 memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
423 if ((ioctl(fd, SIOCGARP, &arp)))
424 ret = ERROR_INVALID_DATA;
425 else {
426 /* FIXME: heh: who said it was ethernet? */
427 int addrLen = ETH_ALEN;
429 if (addrLen > *len) {
430 ret = ERROR_INSUFFICIENT_BUFFER;
431 *len = addrLen;
433 else {
434 if (addrLen > 0)
435 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
436 /* zero out remaining bytes for broken implementations */
437 memset(addr + addrLen, 0, *len - addrLen);
438 *len = addrLen;
439 *type = MIB_IF_TYPE_ETHERNET;
440 ret = NO_ERROR;
444 close(fd);
446 else
447 ret = ERROR_NO_MORE_FILES;
449 return ret;
451 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
452 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
453 PDWORD type)
455 DWORD ret;
456 struct if_msghdr *ifm;
457 struct sockaddr_dl *sdl;
458 u_char *p, *buf;
459 size_t mibLen;
460 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
461 int addrLen;
462 BOOL found = FALSE;
464 if (!name || !len || !addr || !type)
465 return ERROR_INVALID_PARAMETER;
467 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
468 return ERROR_NO_MORE_FILES;
470 buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
471 if (!buf)
472 return ERROR_NOT_ENOUGH_MEMORY;
474 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
475 HeapFree(GetProcessHeap(), 0, buf);
476 return ERROR_NO_MORE_FILES;
479 ret = ERROR_INVALID_DATA;
480 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
481 ifm = (struct if_msghdr *)p;
482 sdl = (struct sockaddr_dl *)(ifm + 1);
484 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
485 continue;
487 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
488 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
489 continue;
491 found = TRUE;
492 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
493 if (addrLen > *len) {
494 ret = ERROR_INSUFFICIENT_BUFFER;
495 *len = addrLen;
497 else {
498 if (addrLen > 0)
499 memcpy(addr, LLADDR(sdl), addrLen);
500 /* zero out remaining bytes for broken implementations */
501 memset(addr + addrLen, 0, *len - addrLen);
502 *len = addrLen;
503 #if defined(HAVE_NET_IF_TYPES_H)
504 switch (sdl->sdl_type)
506 case IFT_ETHER:
507 *type = MIB_IF_TYPE_ETHERNET;
508 break;
509 case IFT_FDDI:
510 *type = MIB_IF_TYPE_FDDI;
511 break;
512 case IFT_ISO88024: /* Token Bus */
513 *type = MIB_IF_TYPE_TOKENRING;
514 break;
515 case IFT_ISO88025: /* Token Ring */
516 *type = MIB_IF_TYPE_TOKENRING;
517 break;
518 case IFT_PPP:
519 *type = MIB_IF_TYPE_PPP;
520 break;
521 case IFT_SLIP:
522 *type = MIB_IF_TYPE_SLIP;
523 break;
524 case IFT_LOOP:
525 *type = MIB_IF_TYPE_LOOPBACK;
526 break;
527 default:
528 *type = MIB_IF_TYPE_OTHER;
530 #else
531 /* default if we don't know */
532 *type = MIB_IF_TYPE_ETHERNET;
533 #endif
534 ret = NO_ERROR;
537 HeapFree(GetProcessHeap(), 0, buf);
538 return ret;
540 #endif
542 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
543 PDWORD type)
545 char nameBuf[IF_NAMESIZE];
546 char *name = getInterfaceNameByIndex(index, nameBuf);
548 if (name)
549 return getInterfacePhysicalByName(name, len, addr, type);
550 else
551 return ERROR_INVALID_DATA;
554 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
556 DWORD ret;
557 int fd;
559 if (!name)
560 return ERROR_INVALID_PARAMETER;
561 if (!mtu)
562 return ERROR_INVALID_PARAMETER;
564 fd = socket(PF_INET, SOCK_DGRAM, 0);
565 if (fd != -1) {
566 struct ifreq ifr;
568 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
569 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
570 ret = ERROR_INVALID_DATA;
571 else {
572 #ifndef __sun
573 *mtu = ifr.ifr_mtu;
574 #else
575 *mtu = ifr.ifr_metric;
576 #endif
577 ret = NO_ERROR;
579 close(fd);
581 else
582 ret = ERROR_NO_MORE_FILES;
583 return ret;
586 DWORD getInterfaceStatusByName(const char *name, PDWORD status)
588 DWORD ret;
589 int fd;
591 if (!name)
592 return ERROR_INVALID_PARAMETER;
593 if (!status)
594 return ERROR_INVALID_PARAMETER;
596 fd = socket(PF_INET, SOCK_DGRAM, 0);
597 if (fd != -1) {
598 struct ifreq ifr;
600 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
601 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
602 ret = ERROR_INVALID_DATA;
603 else {
604 if (ifr.ifr_flags & IFF_UP)
605 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
606 else
607 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
608 ret = NO_ERROR;
610 close(fd);
612 else
613 ret = ERROR_NO_MORE_FILES;
614 return ret;
617 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
619 BYTE addr[MAX_INTERFACE_PHYSADDR];
620 DWORD ret, len = sizeof(addr), type;
622 if (!name)
623 return ERROR_INVALID_PARAMETER;
624 if (!entry)
625 return ERROR_INVALID_PARAMETER;
627 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
628 WCHAR *assigner;
629 const char *walker;
631 memset(entry, 0, sizeof(MIB_IFROW));
632 for (assigner = entry->wszName, walker = name; *walker;
633 walker++, assigner++)
634 *assigner = *walker;
635 *assigner = 0;
636 getInterfaceIndexByName(name, &entry->dwIndex);
637 entry->dwPhysAddrLen = len;
638 memcpy(entry->bPhysAddr, addr, len);
639 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
640 entry->dwType = type;
641 /* FIXME: how to calculate real speed? */
642 getInterfaceMtuByName(name, &entry->dwMtu);
643 /* lie, there's no "administratively down" here */
644 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
645 getInterfaceStatusByName(name, &entry->dwOperStatus);
646 /* punt on dwLastChange? */
647 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
648 memcpy(entry->bDescr, name, entry->dwDescrLen);
649 entry->bDescr[entry->dwDescrLen] = '\0';
650 entry->dwDescrLen++;
651 ret = NO_ERROR;
653 else
654 ret = ERROR_INVALID_DATA;
655 return ret;
658 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
659 * the count to you in *pcAddresses. It also returns to you the struct ifconf
660 * used by the call to ioctl, so that you may process the addresses further.
661 * Free ifc->ifc_buf using HeapFree.
662 * Returns NO_ERROR on success, something else on failure.
664 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
666 DWORD ret;
667 int fd;
669 fd = socket(PF_INET, SOCK_DGRAM, 0);
670 if (fd != -1) {
671 int ioctlRet = 0;
672 DWORD guessedNumAddresses = 0, numAddresses = 0;
673 caddr_t ifPtr;
674 int lastlen;
676 ret = NO_ERROR;
677 ifc->ifc_len = 0;
678 ifc->ifc_buf = NULL;
679 /* there is no way to know the interface count beforehand,
680 so we need to loop again and again upping our max each time
681 until returned is constant across 2 calls */
682 do {
683 lastlen = ifc->ifc_len;
684 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
685 if (guessedNumAddresses == 0)
686 guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
687 else
688 guessedNumAddresses *= 2;
689 ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
690 ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
691 ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
692 } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
694 if (ioctlRet == 0) {
695 ifPtr = ifc->ifc_buf;
696 while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
697 struct ifreq *ifr = (struct ifreq *)ifPtr;
699 if (ifr->ifr_addr.sa_family == AF_INET)
700 numAddresses++;
702 ifPtr += ifreq_len((struct ifreq *)ifPtr);
705 else
706 ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
707 if (!ret)
708 *pcAddresses = numAddresses;
709 else
711 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
712 ifc->ifc_buf = NULL;
714 close(fd);
716 else
717 ret = ERROR_NO_SYSTEM_RESOURCES;
718 return ret;
721 DWORD getNumIPAddresses(void)
723 DWORD numAddresses = 0;
724 struct ifconf ifc;
726 if (!enumIPAddresses(&numAddresses, &ifc))
727 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
728 return numAddresses;
731 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
733 DWORD ret;
735 if (!ppIpAddrTable)
736 ret = ERROR_INVALID_PARAMETER;
737 else
739 DWORD numAddresses = 0;
740 struct ifconf ifc;
742 ret = enumIPAddresses(&numAddresses, &ifc);
743 if (!ret)
745 DWORD size = sizeof(MIB_IPADDRTABLE);
747 if (numAddresses > 1)
748 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
749 *ppIpAddrTable = HeapAlloc(heap, flags, size);
750 if (*ppIpAddrTable) {
751 DWORD i = 0, bcast;
752 caddr_t ifPtr;
754 ret = NO_ERROR;
755 (*ppIpAddrTable)->dwNumEntries = numAddresses;
756 ifPtr = ifc.ifc_buf;
757 while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
758 struct ifreq *ifr = (struct ifreq *)ifPtr;
760 ifPtr += ifreq_len(ifr);
762 if (ifr->ifr_addr.sa_family != AF_INET)
763 continue;
765 ret = getInterfaceIndexByName(ifr->ifr_name,
766 &(*ppIpAddrTable)->table[i].dwIndex);
767 memcpy(&(*ppIpAddrTable)->table[i].dwAddr, ifr->ifr_addr.sa_data + 2,
768 sizeof(DWORD));
769 (*ppIpAddrTable)->table[i].dwMask =
770 getInterfaceMaskByName(ifr->ifr_name);
771 /* the dwBCastAddr member isn't the broadcast address, it indicates
772 * whether the interface uses the 1's broadcast address (1) or the
773 * 0's broadcast address (0).
775 bcast = getInterfaceBCastAddrByName(ifr->ifr_name);
776 (*ppIpAddrTable)->table[i].dwBCastAddr =
777 (bcast & (*ppIpAddrTable)->table[i].dwMask) ? 1 : 0;
778 /* FIXME: hardcoded reasm size, not sure where to get it */
779 (*ppIpAddrTable)->table[i].dwReasmSize = 65535;
781 (*ppIpAddrTable)->table[i].unused1 = 0;
782 (*ppIpAddrTable)->table[i].wType = 0;
783 i++;
786 else
787 ret = ERROR_OUTOFMEMORY;
788 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
791 return ret;
794 #ifdef HAVE_IFADDRS_H
795 ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
797 struct ifaddrs *ifa;
798 ULONG ret;
800 if (!getifaddrs(&ifa))
802 struct ifaddrs *p;
803 ULONG n;
804 char name[IFNAMSIZ];
806 getInterfaceNameByIndex(index, name);
807 for (p = ifa, n = 0; p; p = p->ifa_next)
808 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
809 !strcmp(name, p->ifa_name))
810 n++;
811 if (n)
813 *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
814 sizeof(struct WS_sockaddr_in6)));
815 if (*addrs)
817 struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
818 (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
820 for (p = ifa, n = 0; p; p = p->ifa_next)
822 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
823 !strcmp(name, p->ifa_name))
825 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
827 next_addr->sin6_family = WS_AF_INET6;
828 next_addr->sin6_port = addr->sin6_port;
829 next_addr->sin6_flowinfo = addr->sin6_flowinfo;
830 memcpy(&next_addr->sin6_addr, &addr->sin6_addr,
831 sizeof(next_addr->sin6_addr));
832 next_addr->sin6_scope_id = addr->sin6_scope_id;
833 (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
834 (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
835 next_addr++;
836 n++;
839 *num_addrs = n;
840 ret = ERROR_SUCCESS;
842 else
843 ret = ERROR_OUTOFMEMORY;
845 else
847 *addrs = NULL;
848 *num_addrs = 0;
849 ret = ERROR_SUCCESS;
851 freeifaddrs(ifa);
853 else
854 ret = ERROR_NO_DATA;
855 return ret;
857 #else
858 ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
860 *addrs = NULL;
861 *num_addrs = 0;
862 return ERROR_SUCCESS;
864 #endif
866 char *toIPAddressString(unsigned int addr, char string[16])
868 if (string) {
869 struct in_addr iAddr;
871 iAddr.s_addr = addr;
872 /* extra-anal, just to make auditors happy */
873 lstrcpynA(string, inet_ntoa(iAddr), 16);
875 return string;