msxml3: Implement comment node.
[wine] / dlls / iphlpapi / ifenum.c
1 /* Copyright (C) 2003,2006 Juan Lang
2  *
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.
7  *
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.
12  *
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
16  *
17  * Implementation notes
18  * FIXME:
19  * - I don't support IPv6 addresses here, since SIOCGIFCONF can't return them
20  *
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 MacOSX)
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.
28  */
29
30 #include "config.h"
31
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #include <sys/types.h>
42
43 #ifdef HAVE_SYS_SOCKET_H
44 #include <sys/socket.h>
45 #endif
46
47 #ifdef HAVE_NETINET_IN_H
48 #include <netinet/in.h>
49 #endif
50
51 #ifdef HAVE_ARPA_INET_H
52 #include <arpa/inet.h>
53 #endif
54
55 #ifdef HAVE_NET_IF_H
56 #include <net/if.h>
57 #endif
58
59 #ifdef HAVE_NET_IF_ARP_H
60 #include <net/if_arp.h>
61 #endif
62
63 #ifdef HAVE_NET_ROUTE_H
64 #include <net/route.h>
65 #endif
66
67 #ifdef HAVE_SYS_IOCTL_H
68 #include <sys/ioctl.h>
69 #endif
70
71 #ifdef HAVE_SYS_SYSCTL_H
72 #include <sys/sysctl.h>
73 #endif
74
75 #ifdef HAVE_SYS_SOCKIO_H
76 #include <sys/sockio.h>
77 #endif
78
79 #ifdef HAVE_NET_IF_DL_H
80 #include <net/if_dl.h>
81 #endif
82
83 #ifdef HAVE_NET_IF_TYPES_H
84 #include <net/if_types.h>
85 #endif
86
87 #include "ifenum.h"
88
89 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
90 #define ifreq_len(ifr) \
91  max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
92 #else
93 #define ifreq_len(ifr) sizeof(struct ifreq)
94 #endif
95
96 #ifndef ETH_ALEN
97 #define ETH_ALEN 6
98 #endif
99
100 #ifndef INADDR_NONE
101 #define INADDR_NONE (~0U)
102 #endif
103
104 #define INITIAL_INTERFACES_ASSUMED 4
105
106 #define INDEX_IS_LOOPBACK 0x00800000
107
108 /* Functions */
109
110 static int isLoopbackInterface(int fd, const char *name)
111 {
112   int ret = 0;
113
114   if (name) {
115     struct ifreq ifr;
116
117     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
118     if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
119       ret = ifr.ifr_flags & IFF_LOOPBACK;
120   }
121   return ret;
122 }
123
124 /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
125  * bytes are necessary.
126  */
127 char *getInterfaceNameByIndex(DWORD index, char *name)
128 {
129   return if_indextoname(index, name);
130 }
131
132 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
133 {
134   DWORD ret;
135   unsigned int idx;
136
137   if (!name)
138     return ERROR_INVALID_PARAMETER;
139   if (!index)
140     return ERROR_INVALID_PARAMETER;
141   idx = if_nametoindex(name);
142   if (idx) {
143     *index = idx;
144     ret = NO_ERROR;
145   }
146   else
147     ret = ERROR_INVALID_DATA;
148   return ret;
149 }
150
151 DWORD getNumNonLoopbackInterfaces(void)
152 {
153   DWORD numInterfaces;
154   int fd = socket(PF_INET, SOCK_DGRAM, 0);
155
156   if (fd != -1) {
157     struct if_nameindex *indexes = if_nameindex();
158
159     if (indexes) {
160       struct if_nameindex *p;
161
162       for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
163         if (!isLoopbackInterface(fd, p->if_name))
164           numInterfaces++;
165       if_freenameindex(indexes);
166     }
167     else
168       numInterfaces = 0;
169     close(fd);
170   }
171   else
172     numInterfaces = 0;
173   return numInterfaces;
174 }
175
176 DWORD getNumInterfaces(void)
177 {
178   DWORD numInterfaces;
179   struct if_nameindex *indexes = if_nameindex();
180
181   if (indexes) {
182     struct if_nameindex *p;
183
184     for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
185       numInterfaces++;
186     if_freenameindex(indexes);
187   }
188   else
189     numInterfaces = 0;
190   return numInterfaces;
191 }
192
193 InterfaceIndexTable *getInterfaceIndexTable(void)
194 {
195   DWORD numInterfaces;
196   InterfaceIndexTable *ret;
197   struct if_nameindex *indexes = if_nameindex();
198
199   if (indexes) {
200     struct if_nameindex *p;
201
202     for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
203       numInterfaces++;
204     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
205      sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
206     if (ret) {
207       for (p = indexes; p && p->if_name; p++)
208         ret->indexes[ret->numIndexes++] = p->if_index;
209     }
210     if_freenameindex(indexes);
211   }
212   else
213     ret = NULL;
214   return ret;
215 }
216
217 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
218 {
219   DWORD numInterfaces;
220   InterfaceIndexTable *ret;
221   int fd = socket(PF_INET, SOCK_DGRAM, 0);
222
223   if (fd != -1) {
224     struct if_nameindex *indexes = if_nameindex();
225
226     if (indexes) {
227       struct if_nameindex *p;
228
229       for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
230         if (!isLoopbackInterface(fd, p->if_name))
231           numInterfaces++;
232       ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
233        sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
234       if (ret) {
235         for (p = indexes; p && p->if_name; p++)
236           if (!isLoopbackInterface(fd, p->if_name))
237             ret->indexes[ret->numIndexes++] = p->if_index;
238       }
239       if_freenameindex(indexes);
240     }
241     else
242       ret = NULL;
243     close(fd);
244   }
245   else
246     ret = NULL;
247   return ret;
248 }
249
250 static DWORD getInterfaceBCastAddrByName(const char *name)
251 {
252   DWORD ret = INADDR_ANY;
253
254   if (name) {
255     int fd = socket(PF_INET, SOCK_DGRAM, 0);
256
257     if (fd != -1) {
258       struct ifreq ifr;
259
260       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
261       if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
262         memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
263       close(fd);
264     }
265   }
266   return ret;
267 }
268
269 static DWORD getInterfaceMaskByName(const char *name)
270 {
271   DWORD ret = INADDR_NONE;
272
273   if (name) {
274     int fd = socket(PF_INET, SOCK_DGRAM, 0);
275
276     if (fd != -1) {
277       struct ifreq ifr;
278
279       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
280       if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
281         memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
282       close(fd);
283     }
284   }
285   return ret;
286 }
287
288 #if defined (SIOCGIFHWADDR)
289 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
290  PDWORD type)
291 {
292   DWORD ret;
293   int fd;
294
295   if (!name || !len || !addr || !type)
296     return ERROR_INVALID_PARAMETER;
297
298   fd = socket(PF_INET, SOCK_DGRAM, 0);
299   if (fd != -1) {
300     struct ifreq ifr;
301
302     memset(&ifr, 0, sizeof(struct ifreq));
303     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
304     if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
305       ret = ERROR_INVALID_DATA;
306     else {
307       unsigned int addrLen;
308
309       switch (ifr.ifr_hwaddr.sa_family)
310       {
311 #ifdef ARPHRD_LOOPBACK
312         case ARPHRD_LOOPBACK:
313           addrLen = 0;
314           *type = MIB_IF_TYPE_LOOPBACK;
315           break;
316 #endif
317 #ifdef ARPHRD_ETHER
318         case ARPHRD_ETHER:
319           addrLen = ETH_ALEN;
320           *type = MIB_IF_TYPE_ETHERNET;
321           break;
322 #endif
323 #ifdef ARPHRD_FDDI
324         case ARPHRD_FDDI:
325           addrLen = ETH_ALEN;
326           *type = MIB_IF_TYPE_FDDI;
327           break;
328 #endif
329 #ifdef ARPHRD_IEEE802
330         case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
331           addrLen = ETH_ALEN;
332           *type = MIB_IF_TYPE_TOKENRING;
333           break;
334 #endif
335 #ifdef ARPHRD_IEEE802_TR
336         case ARPHRD_IEEE802_TR: /* also Token Ring? */
337           addrLen = ETH_ALEN;
338           *type = MIB_IF_TYPE_TOKENRING;
339           break;
340 #endif
341 #ifdef ARPHRD_SLIP
342         case ARPHRD_SLIP:
343           addrLen = 0;
344           *type = MIB_IF_TYPE_SLIP;
345           break;
346 #endif
347 #ifdef ARPHRD_PPP
348         case ARPHRD_PPP:
349           addrLen = 0;
350           *type = MIB_IF_TYPE_PPP;
351           break;
352 #endif
353         default:
354           addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
355           *type = MIB_IF_TYPE_OTHER;
356       }
357       if (addrLen > *len) {
358         ret = ERROR_INSUFFICIENT_BUFFER;
359         *len = addrLen;
360       }
361       else {
362         if (addrLen > 0)
363           memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
364         /* zero out remaining bytes for broken implementations */
365         memset(addr + addrLen, 0, *len - addrLen);
366         *len = addrLen;
367         ret = NO_ERROR;
368       }
369     }
370     close(fd);
371   }
372   else
373     ret = ERROR_NO_MORE_FILES;
374   return ret;
375 }
376 #elif defined (SIOCGARP)
377 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
378  PDWORD type)
379 {
380   DWORD ret;
381   int fd;
382
383   if (!name || !len || !addr || !type)
384     return ERROR_INVALID_PARAMETER;
385
386   fd = socket(PF_INET, SOCK_DGRAM, 0);
387   if (fd != -1) {
388     if (isLoopbackInterface(fd, name)) {
389       *type = MIB_IF_TYPE_LOOPBACK;
390       memset(addr, 0, *len);
391       *len = 0;
392       ret=NOERROR;
393     }
394     else {
395       struct arpreq arp;
396       struct sockaddr_in *saddr;
397       struct ifreq ifr;
398
399       /* get IP addr */
400       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
401       ioctl(fd, SIOCGIFADDR, &ifr);
402       memset(&arp, 0, sizeof(struct arpreq));
403       arp.arp_pa.sa_family = AF_INET;
404       saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
405       saddr->sin_family = AF_INET;
406       memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
407       if ((ioctl(fd, SIOCGARP, &arp)))
408         ret = ERROR_INVALID_DATA;
409       else {
410         /* FIXME:  heh:  who said it was ethernet? */
411         int addrLen = ETH_ALEN;
412
413         if (addrLen > *len) {
414           ret = ERROR_INSUFFICIENT_BUFFER;
415           *len = addrLen;
416         }
417         else {
418           if (addrLen > 0)
419             memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
420           /* zero out remaining bytes for broken implementations */
421           memset(addr + addrLen, 0, *len - addrLen);
422           *len = addrLen;
423           *type = MIB_IF_TYPE_ETHERNET;
424           ret = NO_ERROR;
425         }
426       }
427     }
428     close(fd);
429   }
430     else
431       ret = ERROR_NO_MORE_FILES;
432
433   return ret;
434 }
435 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
436 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
437  PDWORD type)
438 {
439   DWORD ret;
440   struct if_msghdr *ifm;
441   struct sockaddr_dl *sdl;
442   u_char *p, *buf;
443   size_t mibLen;
444   int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
445   int addrLen;
446   BOOL found = FALSE;
447
448   if (!name || !len || !addr || !type)
449     return ERROR_INVALID_PARAMETER;
450
451   if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
452     return ERROR_NO_MORE_FILES;
453
454   buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
455   if (!buf)
456     return ERROR_NOT_ENOUGH_MEMORY;
457
458   if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
459     HeapFree(GetProcessHeap(), 0, buf);
460     return ERROR_NO_MORE_FILES;
461   }
462
463   ret = ERROR_INVALID_DATA;
464   for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
465     ifm = (struct if_msghdr *)p;
466     sdl = (struct sockaddr_dl *)(ifm + 1);
467
468     if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
469       continue;
470
471     if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
472      memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
473       continue;
474
475     found = TRUE;
476     addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
477     if (addrLen > *len) {
478       ret = ERROR_INSUFFICIENT_BUFFER;
479       *len = addrLen;
480     }
481     else {
482       if (addrLen > 0)
483         memcpy(addr, LLADDR(sdl), addrLen);
484       /* zero out remaining bytes for broken implementations */
485       memset(addr + addrLen, 0, *len - addrLen);
486       *len = addrLen;
487 #if defined(HAVE_NET_IF_TYPES_H)
488       switch (sdl->sdl_type)
489       {
490         case IFT_ETHER:
491           *type = MIB_IF_TYPE_ETHERNET;
492           break;
493         case IFT_FDDI:
494           *type = MIB_IF_TYPE_FDDI;
495           break;
496         case IFT_ISO88024: /* Token Bus */
497           *type = MIB_IF_TYPE_TOKENRING;
498           break;
499         case IFT_ISO88025: /* Token Ring */
500           *type = MIB_IF_TYPE_TOKENRING;
501           break;
502         case IFT_PPP:
503           *type = MIB_IF_TYPE_PPP;
504           break;
505         case IFT_SLIP:
506           *type = MIB_IF_TYPE_SLIP;
507           break;
508         case IFT_LOOP:
509           *type = MIB_IF_TYPE_LOOPBACK;
510           break;
511         default:
512           *type = MIB_IF_TYPE_OTHER;
513       }
514 #else
515       /* default if we don't know */
516       *type = MIB_IF_TYPE_ETHERNET;
517 #endif
518       ret = NO_ERROR;
519     }
520   }
521   HeapFree(GetProcessHeap(), 0, buf);
522   return ret;
523 }
524 #endif
525
526 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
527  PDWORD type)
528 {
529   char nameBuf[IF_NAMESIZE];
530   char *name = getInterfaceNameByIndex(index, nameBuf);
531
532   if (name)
533     return getInterfacePhysicalByName(name, len, addr, type);
534   else
535     return ERROR_INVALID_DATA;
536 }
537
538 static DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
539 {
540   DWORD ret;
541   int fd;
542
543   if (!name)
544     return ERROR_INVALID_PARAMETER;
545   if (!mtu)
546     return ERROR_INVALID_PARAMETER;
547
548   fd = socket(PF_INET, SOCK_DGRAM, 0);
549   if (fd != -1) {
550     struct ifreq ifr;
551
552     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
553     if ((ioctl(fd, SIOCGIFMTU, &ifr)))
554       ret = ERROR_INVALID_DATA;
555     else {
556 #ifndef __sun
557       *mtu = ifr.ifr_mtu;
558 #else
559       *mtu = ifr.ifr_metric;
560 #endif
561       ret = NO_ERROR;
562     }
563     close(fd);
564   }
565   else
566     ret = ERROR_NO_MORE_FILES;
567   return ret;
568 }
569
570 static DWORD getInterfaceStatusByName(const char *name, PDWORD status)
571 {
572   DWORD ret;
573   int fd;
574
575   if (!name)
576     return ERROR_INVALID_PARAMETER;
577   if (!status)
578     return ERROR_INVALID_PARAMETER;
579
580   fd = socket(PF_INET, SOCK_DGRAM, 0);
581   if (fd != -1) {
582     struct ifreq ifr;
583
584     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
585     if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
586       ret = ERROR_INVALID_DATA;
587     else {
588       if (ifr.ifr_flags & IFF_UP)
589         *status = MIB_IF_OPER_STATUS_OPERATIONAL;
590       else
591         *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
592       ret = NO_ERROR;
593     }
594     close(fd);
595   }
596   else
597     ret = ERROR_NO_MORE_FILES;
598   return ret;
599 }
600
601 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
602 {
603   BYTE addr[MAX_INTERFACE_PHYSADDR];
604   DWORD ret, len = sizeof(addr), type;
605
606   if (!name)
607     return ERROR_INVALID_PARAMETER;
608   if (!entry)
609     return ERROR_INVALID_PARAMETER;
610
611   if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
612     WCHAR *assigner;
613     const char *walker;
614
615     memset(entry, 0, sizeof(MIB_IFROW));
616     for (assigner = entry->wszName, walker = name; *walker; 
617      walker++, assigner++)
618       *assigner = *walker;
619     *assigner = 0;
620     getInterfaceIndexByName(name, &entry->dwIndex);
621     entry->dwPhysAddrLen = len;
622     memcpy(entry->bPhysAddr, addr, len);
623     memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
624     entry->dwType = type;
625     /* FIXME: how to calculate real speed? */
626     getInterfaceMtuByName(name, &entry->dwMtu);
627     /* lie, there's no "administratively down" here */
628     entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
629     getInterfaceStatusByName(name, &entry->dwOperStatus);
630     /* punt on dwLastChange? */
631     entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
632     memcpy(entry->bDescr, name, entry->dwDescrLen);
633     entry->bDescr[entry->dwDescrLen] = '\0';
634     entry->dwDescrLen++;
635     ret = NO_ERROR;
636   }
637   else
638     ret = ERROR_INVALID_DATA;
639   return ret;
640 }
641
642 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
643 {
644   char nameBuf[IF_NAMESIZE];
645   char *name = getInterfaceNameByIndex(index, nameBuf);
646
647   if (name)
648     return getInterfaceEntryByName(name, entry);
649   else
650     return ERROR_INVALID_DATA;
651 }
652
653 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
654  * the count to you in *pcAddresses.  It also returns to you the struct ifconf
655  * used by the call to ioctl, so that you may process the addresses further.
656  * Free ifc->ifc_buf using HeapFree.
657  * Returns NO_ERROR on success, something else on failure.
658  */
659 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
660 {
661   DWORD ret;
662   int fd;
663
664   fd = socket(PF_INET, SOCK_DGRAM, 0);
665   if (fd != -1) {
666     int ioctlRet = 0;
667     DWORD guessedNumAddresses = 0, numAddresses = 0;
668     caddr_t ifPtr;
669
670     ret = NO_ERROR;
671     ifc->ifc_len = 0;
672     ifc->ifc_buf = NULL;
673     /* there is no way to know the interface count beforehand,
674        so we need to loop again and again upping our max each time
675        until returned < max */
676     do {
677       HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
678       if (guessedNumAddresses == 0)
679         guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
680       else
681         guessedNumAddresses *= 2;
682       ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
683       ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
684       ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
685     } while (ioctlRet == 0 &&
686      ifc->ifc_len == (sizeof(struct ifreq) * guessedNumAddresses));
687
688     if (ioctlRet == 0) {
689       ifPtr = ifc->ifc_buf;
690       while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
691         numAddresses++;
692         ifPtr += ifreq_len((struct ifreq *)ifPtr);
693       }
694     }
695     else
696       ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
697     if (!ret)
698       *pcAddresses = numAddresses;
699     else
700     {
701       HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
702       ifc->ifc_buf = NULL;
703     }
704     close(fd);
705   }
706   else
707     ret = ERROR_NO_SYSTEM_RESOURCES;
708   return ret;
709 }
710
711 DWORD getNumIPAddresses(void)
712 {
713   DWORD numAddresses = 0;
714   struct ifconf ifc;
715
716   if (!enumIPAddresses(&numAddresses, &ifc))
717     HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
718   return numAddresses;
719 }
720
721 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
722 {
723   DWORD ret;
724
725   if (!ppIpAddrTable)
726     ret = ERROR_INVALID_PARAMETER;
727   else
728   {
729     DWORD numAddresses = 0;
730     struct ifconf ifc;
731
732     ret = enumIPAddresses(&numAddresses, &ifc);
733     if (!ret)
734     {
735       *ppIpAddrTable = HeapAlloc(heap, flags, sizeof(MIB_IPADDRTABLE) +
736        (numAddresses - 1) * sizeof(MIB_IPADDRROW));
737       if (*ppIpAddrTable) {
738         DWORD i = 0, bcast;
739         caddr_t ifPtr;
740
741         ret = NO_ERROR;
742         (*ppIpAddrTable)->dwNumEntries = numAddresses;
743         ifPtr = ifc.ifc_buf;
744         while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
745           struct ifreq *ifr = (struct ifreq *)ifPtr;
746
747           ret = getInterfaceIndexByName(ifr->ifr_name,
748            &(*ppIpAddrTable)->table[i].dwIndex);
749           memcpy(&(*ppIpAddrTable)->table[i].dwAddr, ifr->ifr_addr.sa_data + 2,
750            sizeof(DWORD));
751           (*ppIpAddrTable)->table[i].dwMask =
752            getInterfaceMaskByName(ifr->ifr_name);
753           /* the dwBCastAddr member isn't the broadcast address, it indicates
754            * whether the interface uses the 1's broadcast address (1) or the
755            * 0's broadcast address (0).
756            */
757           bcast = getInterfaceBCastAddrByName(ifr->ifr_name);
758           (*ppIpAddrTable)->table[i].dwBCastAddr =
759            (bcast & (*ppIpAddrTable)->table[i].dwMask) ? 1 : 0;
760           /* FIXME: hardcoded reasm size, not sure where to get it */
761           (*ppIpAddrTable)->table[i].dwReasmSize = 65535;
762
763           (*ppIpAddrTable)->table[i].unused1 = 0;
764           (*ppIpAddrTable)->table[i].wType = 0;
765           ifPtr += ifreq_len(ifr);
766           i++;
767         }
768       }
769       else
770         ret = ERROR_OUTOFMEMORY;
771       HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
772     }
773   }
774   return ret;
775 }
776
777 char *toIPAddressString(unsigned int addr, char string[16])
778 {
779   if (string) {
780     struct in_addr iAddr;
781
782     iAddr.s_addr = addr;
783     /* extra-anal, just to make auditors happy */
784     lstrcpynA(string, inet_ntoa(iAddr), 16);
785   }
786   return string;
787 }