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