msi: Use MsgWaitForMultipleObjectsEx to do waits.
[wine/multimedia.git] / dlls / iphlpapi / ifenum.c
bloba0d75777b9cd6e9b726152fc6ec896fcbf009cca
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 BOOL isIfIndexLoopback(ULONG idx)
163 BOOL ret = FALSE;
164 char name[IFNAMSIZ];
165 int fd;
167 getInterfaceNameByIndex(idx, name);
168 fd = socket(PF_INET, SOCK_DGRAM, 0);
169 if (fd != -1) {
170 ret = isLoopbackInterface(fd, name);
171 close(fd);
173 return ret;
176 DWORD getNumNonLoopbackInterfaces(void)
178 DWORD numInterfaces;
179 int fd = socket(PF_INET, SOCK_DGRAM, 0);
181 if (fd != -1) {
182 struct if_nameindex *indexes = if_nameindex();
184 if (indexes) {
185 struct if_nameindex *p;
187 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
188 if (!isLoopbackInterface(fd, p->if_name))
189 numInterfaces++;
190 if_freenameindex(indexes);
192 else
193 numInterfaces = 0;
194 close(fd);
196 else
197 numInterfaces = 0;
198 return numInterfaces;
201 DWORD getNumInterfaces(void)
203 DWORD numInterfaces;
204 struct if_nameindex *indexes = if_nameindex();
206 if (indexes) {
207 struct if_nameindex *p;
209 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
210 numInterfaces++;
211 if_freenameindex(indexes);
213 else
214 numInterfaces = 0;
215 return numInterfaces;
218 InterfaceIndexTable *getInterfaceIndexTable(void)
220 DWORD numInterfaces;
221 InterfaceIndexTable *ret;
222 struct if_nameindex *indexes = if_nameindex();
224 if (indexes) {
225 struct if_nameindex *p;
226 DWORD size = sizeof(InterfaceIndexTable);
228 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
229 numInterfaces++;
230 if (numInterfaces > 1)
231 size += (numInterfaces - 1) * sizeof(DWORD);
232 ret = HeapAlloc(GetProcessHeap(), 0, size);
233 if (ret) {
234 ret->numIndexes = 0;
235 for (p = indexes; p && p->if_name; p++)
236 ret->indexes[ret->numIndexes++] = p->if_index;
238 if_freenameindex(indexes);
240 else
241 ret = NULL;
242 return ret;
245 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
247 DWORD numInterfaces;
248 InterfaceIndexTable *ret;
249 int fd = socket(PF_INET, SOCK_DGRAM, 0);
251 if (fd != -1) {
252 struct if_nameindex *indexes = if_nameindex();
254 if (indexes) {
255 struct if_nameindex *p;
256 DWORD size = sizeof(InterfaceIndexTable);
258 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
259 if (!isLoopbackInterface(fd, p->if_name))
260 numInterfaces++;
261 if (numInterfaces > 1)
262 size += (numInterfaces - 1) * sizeof(DWORD);
263 ret = HeapAlloc(GetProcessHeap(), 0, size);
264 if (ret) {
265 ret->numIndexes = 0;
266 for (p = indexes; p && p->if_name; p++)
267 if (!isLoopbackInterface(fd, p->if_name))
268 ret->indexes[ret->numIndexes++] = p->if_index;
270 if_freenameindex(indexes);
272 else
273 ret = NULL;
274 close(fd);
276 else
277 ret = NULL;
278 return ret;
281 static DWORD getInterfaceBCastAddrByName(const char *name)
283 DWORD ret = INADDR_ANY;
285 if (name) {
286 int fd = socket(PF_INET, SOCK_DGRAM, 0);
288 if (fd != -1) {
289 struct ifreq ifr;
291 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
292 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
293 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
294 close(fd);
297 return ret;
300 static DWORD getInterfaceMaskByName(const char *name)
302 DWORD ret = INADDR_NONE;
304 if (name) {
305 int fd = socket(PF_INET, SOCK_DGRAM, 0);
307 if (fd != -1) {
308 struct ifreq ifr;
310 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
311 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
312 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
313 close(fd);
316 return ret;
319 #if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
320 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
321 PDWORD type)
323 DWORD ret;
324 int fd;
326 if (!name || !len || !addr || !type)
327 return ERROR_INVALID_PARAMETER;
329 fd = socket(PF_INET, SOCK_DGRAM, 0);
330 if (fd != -1) {
331 struct ifreq ifr;
333 memset(&ifr, 0, sizeof(struct ifreq));
334 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
335 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
336 ret = ERROR_INVALID_DATA;
337 else {
338 unsigned int addrLen;
340 switch (ifr.ifr_hwaddr.sa_family)
342 #ifdef ARPHRD_LOOPBACK
343 case ARPHRD_LOOPBACK:
344 addrLen = 0;
345 *type = MIB_IF_TYPE_LOOPBACK;
346 break;
347 #endif
348 #ifdef ARPHRD_ETHER
349 case ARPHRD_ETHER:
350 addrLen = ETH_ALEN;
351 *type = MIB_IF_TYPE_ETHERNET;
352 break;
353 #endif
354 #ifdef ARPHRD_FDDI
355 case ARPHRD_FDDI:
356 addrLen = ETH_ALEN;
357 *type = MIB_IF_TYPE_FDDI;
358 break;
359 #endif
360 #ifdef ARPHRD_IEEE802
361 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
362 addrLen = ETH_ALEN;
363 *type = MIB_IF_TYPE_TOKENRING;
364 break;
365 #endif
366 #ifdef ARPHRD_IEEE802_TR
367 case ARPHRD_IEEE802_TR: /* also Token Ring? */
368 addrLen = ETH_ALEN;
369 *type = MIB_IF_TYPE_TOKENRING;
370 break;
371 #endif
372 #ifdef ARPHRD_SLIP
373 case ARPHRD_SLIP:
374 addrLen = 0;
375 *type = MIB_IF_TYPE_SLIP;
376 break;
377 #endif
378 #ifdef ARPHRD_PPP
379 case ARPHRD_PPP:
380 addrLen = 0;
381 *type = MIB_IF_TYPE_PPP;
382 break;
383 #endif
384 default:
385 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
386 *type = MIB_IF_TYPE_OTHER;
388 if (addrLen > *len) {
389 ret = ERROR_INSUFFICIENT_BUFFER;
390 *len = addrLen;
392 else {
393 if (addrLen > 0)
394 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
395 /* zero out remaining bytes for broken implementations */
396 memset(addr + addrLen, 0, *len - addrLen);
397 *len = addrLen;
398 ret = NO_ERROR;
401 close(fd);
403 else
404 ret = ERROR_NO_MORE_FILES;
405 return ret;
407 #elif defined (SIOCGARP)
408 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
409 PDWORD type)
411 DWORD ret;
412 int fd;
414 if (!name || !len || !addr || !type)
415 return ERROR_INVALID_PARAMETER;
417 fd = socket(PF_INET, SOCK_DGRAM, 0);
418 if (fd != -1) {
419 if (isLoopbackInterface(fd, name)) {
420 *type = MIB_IF_TYPE_LOOPBACK;
421 memset(addr, 0, *len);
422 *len = 0;
423 ret=NOERROR;
425 else {
426 struct arpreq arp;
427 struct sockaddr_in *saddr;
428 struct ifreq ifr;
430 /* get IP addr */
431 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
432 ioctl(fd, SIOCGIFADDR, &ifr);
433 memset(&arp, 0, sizeof(struct arpreq));
434 arp.arp_pa.sa_family = AF_INET;
435 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
436 saddr->sin_family = AF_INET;
437 memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
438 if ((ioctl(fd, SIOCGARP, &arp)))
439 ret = ERROR_INVALID_DATA;
440 else {
441 /* FIXME: heh: who said it was ethernet? */
442 int addrLen = ETH_ALEN;
444 if (addrLen > *len) {
445 ret = ERROR_INSUFFICIENT_BUFFER;
446 *len = addrLen;
448 else {
449 if (addrLen > 0)
450 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
451 /* zero out remaining bytes for broken implementations */
452 memset(addr + addrLen, 0, *len - addrLen);
453 *len = addrLen;
454 *type = MIB_IF_TYPE_ETHERNET;
455 ret = NO_ERROR;
459 close(fd);
461 else
462 ret = ERROR_NO_MORE_FILES;
464 return ret;
466 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
467 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
468 PDWORD type)
470 DWORD ret;
471 struct if_msghdr *ifm;
472 struct sockaddr_dl *sdl;
473 u_char *p, *buf;
474 size_t mibLen;
475 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
476 unsigned addrLen;
477 BOOL found = FALSE;
479 if (!name || !len || !addr || !type)
480 return ERROR_INVALID_PARAMETER;
482 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
483 return ERROR_NO_MORE_FILES;
485 buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
486 if (!buf)
487 return ERROR_NOT_ENOUGH_MEMORY;
489 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
490 HeapFree(GetProcessHeap(), 0, buf);
491 return ERROR_NO_MORE_FILES;
494 ret = ERROR_INVALID_DATA;
495 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
496 ifm = (struct if_msghdr *)p;
497 sdl = (struct sockaddr_dl *)(ifm + 1);
499 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
500 continue;
502 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
503 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
504 continue;
506 found = TRUE;
507 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
508 if (addrLen > *len) {
509 ret = ERROR_INSUFFICIENT_BUFFER;
510 *len = addrLen;
512 else {
513 if (addrLen > 0)
514 memcpy(addr, LLADDR(sdl), addrLen);
515 /* zero out remaining bytes for broken implementations */
516 memset(addr + addrLen, 0, *len - addrLen);
517 *len = addrLen;
518 #if defined(HAVE_NET_IF_TYPES_H)
519 switch (sdl->sdl_type)
521 case IFT_ETHER:
522 *type = MIB_IF_TYPE_ETHERNET;
523 break;
524 case IFT_FDDI:
525 *type = MIB_IF_TYPE_FDDI;
526 break;
527 case IFT_ISO88024: /* Token Bus */
528 *type = MIB_IF_TYPE_TOKENRING;
529 break;
530 case IFT_ISO88025: /* Token Ring */
531 *type = MIB_IF_TYPE_TOKENRING;
532 break;
533 case IFT_PPP:
534 *type = MIB_IF_TYPE_PPP;
535 break;
536 case IFT_SLIP:
537 *type = MIB_IF_TYPE_SLIP;
538 break;
539 case IFT_LOOP:
540 *type = MIB_IF_TYPE_LOOPBACK;
541 break;
542 default:
543 *type = MIB_IF_TYPE_OTHER;
545 #else
546 /* default if we don't know */
547 *type = MIB_IF_TYPE_ETHERNET;
548 #endif
549 ret = NO_ERROR;
552 HeapFree(GetProcessHeap(), 0, buf);
553 return ret;
555 #endif
557 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
558 PDWORD type)
560 char nameBuf[IF_NAMESIZE];
561 char *name = getInterfaceNameByIndex(index, nameBuf);
563 if (name)
564 return getInterfacePhysicalByName(name, len, addr, type);
565 else
566 return ERROR_INVALID_DATA;
569 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
571 DWORD ret;
572 int fd;
574 if (!name)
575 return ERROR_INVALID_PARAMETER;
576 if (!mtu)
577 return ERROR_INVALID_PARAMETER;
579 fd = socket(PF_INET, SOCK_DGRAM, 0);
580 if (fd != -1) {
581 struct ifreq ifr;
583 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
584 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
585 ret = ERROR_INVALID_DATA;
586 else {
587 #ifndef __sun
588 *mtu = ifr.ifr_mtu;
589 #else
590 *mtu = ifr.ifr_metric;
591 #endif
592 ret = NO_ERROR;
594 close(fd);
596 else
597 ret = ERROR_NO_MORE_FILES;
598 return ret;
601 DWORD getInterfaceStatusByName(const char *name, PDWORD status)
603 DWORD ret;
604 int fd;
606 if (!name)
607 return ERROR_INVALID_PARAMETER;
608 if (!status)
609 return ERROR_INVALID_PARAMETER;
611 fd = socket(PF_INET, SOCK_DGRAM, 0);
612 if (fd != -1) {
613 struct ifreq ifr;
615 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
616 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
617 ret = ERROR_INVALID_DATA;
618 else {
619 if (ifr.ifr_flags & IFF_UP)
620 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
621 else
622 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
623 ret = NO_ERROR;
625 close(fd);
627 else
628 ret = ERROR_NO_MORE_FILES;
629 return ret;
632 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
634 BYTE addr[MAX_INTERFACE_PHYSADDR];
635 DWORD ret, len = sizeof(addr), type;
637 if (!name)
638 return ERROR_INVALID_PARAMETER;
639 if (!entry)
640 return ERROR_INVALID_PARAMETER;
642 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
643 WCHAR *assigner;
644 const char *walker;
646 memset(entry, 0, sizeof(MIB_IFROW));
647 for (assigner = entry->wszName, walker = name; *walker;
648 walker++, assigner++)
649 *assigner = *walker;
650 *assigner = 0;
651 getInterfaceIndexByName(name, &entry->dwIndex);
652 entry->dwPhysAddrLen = len;
653 memcpy(entry->bPhysAddr, addr, len);
654 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
655 entry->dwType = type;
656 /* FIXME: how to calculate real speed? */
657 getInterfaceMtuByName(name, &entry->dwMtu);
658 /* lie, there's no "administratively down" here */
659 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
660 getInterfaceStatusByName(name, &entry->dwOperStatus);
661 /* punt on dwLastChange? */
662 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
663 memcpy(entry->bDescr, name, entry->dwDescrLen);
664 entry->bDescr[entry->dwDescrLen] = '\0';
665 entry->dwDescrLen++;
666 ret = NO_ERROR;
668 else
669 ret = ERROR_INVALID_DATA;
670 return ret;
673 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
674 * the count to you in *pcAddresses. It also returns to you the struct ifconf
675 * used by the call to ioctl, so that you may process the addresses further.
676 * Free ifc->ifc_buf using HeapFree.
677 * Returns NO_ERROR on success, something else on failure.
679 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
681 DWORD ret;
682 int fd;
684 fd = socket(PF_INET, SOCK_DGRAM, 0);
685 if (fd != -1) {
686 int ioctlRet = 0;
687 DWORD guessedNumAddresses = 0, numAddresses = 0;
688 caddr_t ifPtr;
689 int lastlen;
691 ret = NO_ERROR;
692 ifc->ifc_len = 0;
693 ifc->ifc_buf = NULL;
694 /* there is no way to know the interface count beforehand,
695 so we need to loop again and again upping our max each time
696 until returned is constant across 2 calls */
697 do {
698 lastlen = ifc->ifc_len;
699 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
700 if (guessedNumAddresses == 0)
701 guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
702 else
703 guessedNumAddresses *= 2;
704 ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
705 ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
706 ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
707 } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
709 if (ioctlRet == 0) {
710 ifPtr = ifc->ifc_buf;
711 while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
712 struct ifreq *ifr = (struct ifreq *)ifPtr;
714 if (ifr->ifr_addr.sa_family == AF_INET)
715 numAddresses++;
717 ifPtr += ifreq_len((struct ifreq *)ifPtr);
720 else
721 ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
722 if (!ret)
723 *pcAddresses = numAddresses;
724 else
726 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
727 ifc->ifc_buf = NULL;
729 close(fd);
731 else
732 ret = ERROR_NO_SYSTEM_RESOURCES;
733 return ret;
736 DWORD getNumIPAddresses(void)
738 DWORD numAddresses = 0;
739 struct ifconf ifc;
741 if (!enumIPAddresses(&numAddresses, &ifc))
742 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
743 return numAddresses;
746 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
748 DWORD ret;
750 if (!ppIpAddrTable)
751 ret = ERROR_INVALID_PARAMETER;
752 else
754 DWORD numAddresses = 0;
755 struct ifconf ifc;
757 ret = enumIPAddresses(&numAddresses, &ifc);
758 if (!ret)
760 DWORD size = sizeof(MIB_IPADDRTABLE);
762 if (numAddresses > 1)
763 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
764 *ppIpAddrTable = HeapAlloc(heap, flags, size);
765 if (*ppIpAddrTable) {
766 DWORD i = 0, bcast;
767 caddr_t ifPtr;
769 ret = NO_ERROR;
770 (*ppIpAddrTable)->dwNumEntries = numAddresses;
771 ifPtr = ifc.ifc_buf;
772 while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
773 struct ifreq *ifr = (struct ifreq *)ifPtr;
775 ifPtr += ifreq_len(ifr);
777 if (ifr->ifr_addr.sa_family != AF_INET)
778 continue;
780 ret = getInterfaceIndexByName(ifr->ifr_name,
781 &(*ppIpAddrTable)->table[i].dwIndex);
782 memcpy(&(*ppIpAddrTable)->table[i].dwAddr, ifr->ifr_addr.sa_data + 2,
783 sizeof(DWORD));
784 (*ppIpAddrTable)->table[i].dwMask =
785 getInterfaceMaskByName(ifr->ifr_name);
786 /* the dwBCastAddr member isn't the broadcast address, it indicates
787 * whether the interface uses the 1's broadcast address (1) or the
788 * 0's broadcast address (0).
790 bcast = getInterfaceBCastAddrByName(ifr->ifr_name);
791 (*ppIpAddrTable)->table[i].dwBCastAddr =
792 (bcast & (*ppIpAddrTable)->table[i].dwMask) ? 1 : 0;
793 /* FIXME: hardcoded reasm size, not sure where to get it */
794 (*ppIpAddrTable)->table[i].dwReasmSize = 65535;
796 (*ppIpAddrTable)->table[i].unused1 = 0;
797 (*ppIpAddrTable)->table[i].wType = 0;
798 i++;
801 else
802 ret = ERROR_OUTOFMEMORY;
803 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
806 return ret;
809 #ifdef HAVE_IFADDRS_H
810 ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
812 struct ifaddrs *ifa;
813 ULONG ret;
815 if (!getifaddrs(&ifa))
817 struct ifaddrs *p;
818 ULONG n;
819 char name[IFNAMSIZ];
821 getInterfaceNameByIndex(index, name);
822 for (p = ifa, n = 0; p; p = p->ifa_next)
823 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
824 !strcmp(name, p->ifa_name))
825 n++;
826 if (n)
828 *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
829 sizeof(struct WS_sockaddr_in6)));
830 if (*addrs)
832 struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
833 (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
835 for (p = ifa, n = 0; p; p = p->ifa_next)
837 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
838 !strcmp(name, p->ifa_name))
840 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
842 next_addr->sin6_family = WS_AF_INET6;
843 next_addr->sin6_port = addr->sin6_port;
844 next_addr->sin6_flowinfo = addr->sin6_flowinfo;
845 memcpy(&next_addr->sin6_addr, &addr->sin6_addr,
846 sizeof(next_addr->sin6_addr));
847 next_addr->sin6_scope_id = addr->sin6_scope_id;
848 (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
849 (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
850 next_addr++;
851 n++;
854 *num_addrs = n;
855 ret = ERROR_SUCCESS;
857 else
858 ret = ERROR_OUTOFMEMORY;
860 else
862 *addrs = NULL;
863 *num_addrs = 0;
864 ret = ERROR_SUCCESS;
866 freeifaddrs(ifa);
868 else
869 ret = ERROR_NO_DATA;
870 return ret;
872 #else
873 ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
875 *addrs = NULL;
876 *num_addrs = 0;
877 return ERROR_SUCCESS;
879 #endif
881 char *toIPAddressString(unsigned int addr, char string[16])
883 if (string) {
884 struct in_addr iAddr;
886 iAddr.s_addr = addr;
887 /* extra-anal, just to make auditors happy */
888 lstrcpynA(string, inet_ntoa(iAddr), 16);
890 return string;