kernel32/tests: Get the test to run on Windows 95.
[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 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.
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 #ifdef HAVE_SYS_PARAM_H
43 #include <sys/param.h>
44 #endif
45
46 #ifdef HAVE_SYS_SOCKET_H
47 #include <sys/socket.h>
48 #endif
49
50 #ifdef HAVE_NETINET_IN_H
51 #include <netinet/in.h>
52 #endif
53
54 #ifdef HAVE_ARPA_INET_H
55 #include <arpa/inet.h>
56 #endif
57
58 #ifdef HAVE_NET_IF_H
59 #include <net/if.h>
60 #endif
61
62 #ifdef HAVE_NET_IF_ARP_H
63 #include <net/if_arp.h>
64 #endif
65
66 #ifdef HAVE_NET_ROUTE_H
67 #include <net/route.h>
68 #endif
69
70 #ifdef HAVE_SYS_IOCTL_H
71 #include <sys/ioctl.h>
72 #endif
73
74 #ifdef HAVE_SYS_SYSCTL_H
75 #include <sys/sysctl.h>
76 #endif
77
78 #ifdef HAVE_SYS_SOCKIO_H
79 #include <sys/sockio.h>
80 #endif
81
82 #ifdef HAVE_NET_IF_DL_H
83 #include <net/if_dl.h>
84 #endif
85
86 #ifdef HAVE_NET_IF_TYPES_H
87 #include <net/if_types.h>
88 #endif
89
90 #include "ifenum.h"
91
92 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
93 #define ifreq_len(ifr) \
94  max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
95 #else
96 #define ifreq_len(ifr) sizeof(struct ifreq)
97 #endif
98
99 #ifndef ETH_ALEN
100 #define ETH_ALEN 6
101 #endif
102
103 #ifndef IF_NAMESIZE
104 #define IF_NAMESIZE 16
105 #endif
106
107 #ifndef INADDR_NONE
108 #define INADDR_NONE (~0U)
109 #endif
110
111 #define INITIAL_INTERFACES_ASSUMED 4
112
113 #define INDEX_IS_LOOPBACK 0x00800000
114
115 /* Functions */
116
117 static int isLoopbackInterface(int fd, const char *name)
118 {
119   int ret = 0;
120
121   if (name) {
122     struct ifreq ifr;
123
124     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
125     if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
126       ret = ifr.ifr_flags & IFF_LOOPBACK;
127   }
128   return ret;
129 }
130
131 /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
132  * bytes are necessary.
133  */
134 char *getInterfaceNameByIndex(DWORD index, char *name)
135 {
136   return if_indextoname(index, name);
137 }
138
139 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
140 {
141   DWORD ret;
142   unsigned int idx;
143
144   if (!name)
145     return ERROR_INVALID_PARAMETER;
146   if (!index)
147     return ERROR_INVALID_PARAMETER;
148   idx = if_nametoindex(name);
149   if (idx) {
150     *index = idx;
151     ret = NO_ERROR;
152   }
153   else
154     ret = ERROR_INVALID_DATA;
155   return ret;
156 }
157
158 DWORD getNumNonLoopbackInterfaces(void)
159 {
160   DWORD numInterfaces;
161   int fd = socket(PF_INET, SOCK_DGRAM, 0);
162
163   if (fd != -1) {
164     struct if_nameindex *indexes = if_nameindex();
165
166     if (indexes) {
167       struct if_nameindex *p;
168
169       for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
170         if (!isLoopbackInterface(fd, p->if_name))
171           numInterfaces++;
172       if_freenameindex(indexes);
173     }
174     else
175       numInterfaces = 0;
176     close(fd);
177   }
178   else
179     numInterfaces = 0;
180   return numInterfaces;
181 }
182
183 DWORD getNumInterfaces(void)
184 {
185   DWORD numInterfaces;
186   struct if_nameindex *indexes = if_nameindex();
187
188   if (indexes) {
189     struct if_nameindex *p;
190
191     for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
192       numInterfaces++;
193     if_freenameindex(indexes);
194   }
195   else
196     numInterfaces = 0;
197   return numInterfaces;
198 }
199
200 InterfaceIndexTable *getInterfaceIndexTable(void)
201 {
202   DWORD numInterfaces;
203   InterfaceIndexTable *ret;
204   struct if_nameindex *indexes = if_nameindex();
205
206   if (indexes) {
207     struct if_nameindex *p;
208     DWORD size = sizeof(InterfaceIndexTable);
209
210     for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
211       numInterfaces++;
212     if (numInterfaces > 1)
213       size += (numInterfaces - 1) * sizeof(DWORD);
214     ret = HeapAlloc(GetProcessHeap(), 0, size);
215     if (ret) {
216       ret->numIndexes = 0;
217       for (p = indexes; p && p->if_name; p++)
218         ret->indexes[ret->numIndexes++] = p->if_index;
219     }
220     if_freenameindex(indexes);
221   }
222   else
223     ret = NULL;
224   return ret;
225 }
226
227 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
228 {
229   DWORD numInterfaces;
230   InterfaceIndexTable *ret;
231   int fd = socket(PF_INET, SOCK_DGRAM, 0);
232
233   if (fd != -1) {
234     struct if_nameindex *indexes = if_nameindex();
235
236     if (indexes) {
237       struct if_nameindex *p;
238       DWORD size = sizeof(InterfaceIndexTable);
239
240       for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
241         if (!isLoopbackInterface(fd, p->if_name))
242           numInterfaces++;
243       if (numInterfaces > 1)
244         size += (numInterfaces - 1) * sizeof(DWORD);
245       ret = HeapAlloc(GetProcessHeap(), 0, size);
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;
251       }
252       if_freenameindex(indexes);
253     }
254     else
255       ret = NULL;
256     close(fd);
257   }
258   else
259     ret = NULL;
260   return ret;
261 }
262
263 static DWORD getInterfaceBCastAddrByName(const char *name)
264 {
265   DWORD ret = INADDR_ANY;
266
267   if (name) {
268     int fd = socket(PF_INET, SOCK_DGRAM, 0);
269
270     if (fd != -1) {
271       struct ifreq ifr;
272
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);
277     }
278   }
279   return ret;
280 }
281
282 static DWORD getInterfaceMaskByName(const char *name)
283 {
284   DWORD ret = INADDR_NONE;
285
286   if (name) {
287     int fd = socket(PF_INET, SOCK_DGRAM, 0);
288
289     if (fd != -1) {
290       struct ifreq ifr;
291
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);
296     }
297   }
298   return ret;
299 }
300
301 #if defined (SIOCGIFHWADDR)
302 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
303  PDWORD type)
304 {
305   DWORD ret;
306   int fd;
307
308   if (!name || !len || !addr || !type)
309     return ERROR_INVALID_PARAMETER;
310
311   fd = socket(PF_INET, SOCK_DGRAM, 0);
312   if (fd != -1) {
313     struct ifreq ifr;
314
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;
321
322       switch (ifr.ifr_hwaddr.sa_family)
323       {
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;
369       }
370       if (addrLen > *len) {
371         ret = ERROR_INSUFFICIENT_BUFFER;
372         *len = addrLen;
373       }
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;
381       }
382     }
383     close(fd);
384   }
385   else
386     ret = ERROR_NO_MORE_FILES;
387   return ret;
388 }
389 #elif defined (SIOCGARP)
390 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
391  PDWORD type)
392 {
393   DWORD ret;
394   int fd;
395
396   if (!name || !len || !addr || !type)
397     return ERROR_INVALID_PARAMETER;
398
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;
406     }
407     else {
408       struct arpreq arp;
409       struct sockaddr_in *saddr;
410       struct ifreq ifr;
411
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;
425
426         if (addrLen > *len) {
427           ret = ERROR_INSUFFICIENT_BUFFER;
428           *len = addrLen;
429         }
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;
438         }
439       }
440     }
441     close(fd);
442   }
443     else
444       ret = ERROR_NO_MORE_FILES;
445
446   return ret;
447 }
448 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
449 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
450  PDWORD type)
451 {
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   int addrLen;
459   BOOL found = FALSE;
460
461   if (!name || !len || !addr || !type)
462     return ERROR_INVALID_PARAMETER;
463
464   if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
465     return ERROR_NO_MORE_FILES;
466
467   buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
468   if (!buf)
469     return ERROR_NOT_ENOUGH_MEMORY;
470
471   if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
472     HeapFree(GetProcessHeap(), 0, buf);
473     return ERROR_NO_MORE_FILES;
474   }
475
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);
480
481     if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
482       continue;
483
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;
487
488     found = TRUE;
489     addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
490     if (addrLen > *len) {
491       ret = ERROR_INSUFFICIENT_BUFFER;
492       *len = addrLen;
493     }
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)
502       {
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;
526       }
527 #else
528       /* default if we don't know */
529       *type = MIB_IF_TYPE_ETHERNET;
530 #endif
531       ret = NO_ERROR;
532     }
533   }
534   HeapFree(GetProcessHeap(), 0, buf);
535   return ret;
536 }
537 #endif
538
539 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
540  PDWORD type)
541 {
542   char nameBuf[IF_NAMESIZE];
543   char *name = getInterfaceNameByIndex(index, nameBuf);
544
545   if (name)
546     return getInterfacePhysicalByName(name, len, addr, type);
547   else
548     return ERROR_INVALID_DATA;
549 }
550
551 static DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
552 {
553   DWORD ret;
554   int fd;
555
556   if (!name)
557     return ERROR_INVALID_PARAMETER;
558   if (!mtu)
559     return ERROR_INVALID_PARAMETER;
560
561   fd = socket(PF_INET, SOCK_DGRAM, 0);
562   if (fd != -1) {
563     struct ifreq ifr;
564
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;
575     }
576     close(fd);
577   }
578   else
579     ret = ERROR_NO_MORE_FILES;
580   return ret;
581 }
582
583 static DWORD getInterfaceStatusByName(const char *name, PDWORD status)
584 {
585   DWORD ret;
586   int fd;
587
588   if (!name)
589     return ERROR_INVALID_PARAMETER;
590   if (!status)
591     return ERROR_INVALID_PARAMETER;
592
593   fd = socket(PF_INET, SOCK_DGRAM, 0);
594   if (fd != -1) {
595     struct ifreq ifr;
596
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;
606     }
607     close(fd);
608   }
609   else
610     ret = ERROR_NO_MORE_FILES;
611   return ret;
612 }
613
614 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
615 {
616   BYTE addr[MAX_INTERFACE_PHYSADDR];
617   DWORD ret, len = sizeof(addr), type;
618
619   if (!name)
620     return ERROR_INVALID_PARAMETER;
621   if (!entry)
622     return ERROR_INVALID_PARAMETER;
623
624   if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
625     WCHAR *assigner;
626     const char *walker;
627
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;
649   }
650   else
651     ret = ERROR_INVALID_DATA;
652   return ret;
653 }
654
655 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
656 {
657   char nameBuf[IF_NAMESIZE];
658   char *name = getInterfaceNameByIndex(index, nameBuf);
659
660   if (name)
661     return getInterfaceEntryByName(name, entry);
662   else
663     return ERROR_INVALID_DATA;
664 }
665
666 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
667  * the count to you in *pcAddresses.  It also returns to you the struct ifconf
668  * used by the call to ioctl, so that you may process the addresses further.
669  * Free ifc->ifc_buf using HeapFree.
670  * Returns NO_ERROR on success, something else on failure.
671  */
672 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
673 {
674   DWORD ret;
675   int fd;
676
677   fd = socket(PF_INET, SOCK_DGRAM, 0);
678   if (fd != -1) {
679     int ioctlRet = 0;
680     DWORD guessedNumAddresses = 0, numAddresses = 0;
681     caddr_t ifPtr;
682     int lastlen;
683
684     ret = NO_ERROR;
685     ifc->ifc_len = 0;
686     ifc->ifc_buf = NULL;
687     /* there is no way to know the interface count beforehand,
688        so we need to loop again and again upping our max each time
689        until returned is constant across 2 calls */
690     do {
691       lastlen = ifc->ifc_len;
692       HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
693       if (guessedNumAddresses == 0)
694         guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
695       else
696         guessedNumAddresses *= 2;
697       ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
698       ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
699       ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
700     } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
701
702     if (ioctlRet == 0) {
703       ifPtr = ifc->ifc_buf;
704       while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
705         struct ifreq *ifr = (struct ifreq *)ifPtr;
706
707         if (ifr->ifr_addr.sa_family == AF_INET)
708           numAddresses++;
709
710         ifPtr += ifreq_len((struct ifreq *)ifPtr);
711       }
712     }
713     else
714       ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
715     if (!ret)
716       *pcAddresses = numAddresses;
717     else
718     {
719       HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
720       ifc->ifc_buf = NULL;
721     }
722     close(fd);
723   }
724   else
725     ret = ERROR_NO_SYSTEM_RESOURCES;
726   return ret;
727 }
728
729 DWORD getNumIPAddresses(void)
730 {
731   DWORD numAddresses = 0;
732   struct ifconf ifc;
733
734   if (!enumIPAddresses(&numAddresses, &ifc))
735     HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
736   return numAddresses;
737 }
738
739 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
740 {
741   DWORD ret;
742
743   if (!ppIpAddrTable)
744     ret = ERROR_INVALID_PARAMETER;
745   else
746   {
747     DWORD numAddresses = 0;
748     struct ifconf ifc;
749
750     ret = enumIPAddresses(&numAddresses, &ifc);
751     if (!ret)
752     {
753       DWORD size = sizeof(MIB_IPADDRTABLE);
754
755       if (numAddresses > 1)
756         size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
757       *ppIpAddrTable = HeapAlloc(heap, flags, size);
758       if (*ppIpAddrTable) {
759         DWORD i = 0, bcast;
760         caddr_t ifPtr;
761
762         ret = NO_ERROR;
763         (*ppIpAddrTable)->dwNumEntries = numAddresses;
764         ifPtr = ifc.ifc_buf;
765         while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
766           struct ifreq *ifr = (struct ifreq *)ifPtr;
767
768           ifPtr += ifreq_len(ifr);
769
770           if (ifr->ifr_addr.sa_family != AF_INET)
771              continue;
772
773           ret = getInterfaceIndexByName(ifr->ifr_name,
774            &(*ppIpAddrTable)->table[i].dwIndex);
775           memcpy(&(*ppIpAddrTable)->table[i].dwAddr, ifr->ifr_addr.sa_data + 2,
776            sizeof(DWORD));
777           (*ppIpAddrTable)->table[i].dwMask =
778            getInterfaceMaskByName(ifr->ifr_name);
779           /* the dwBCastAddr member isn't the broadcast address, it indicates
780            * whether the interface uses the 1's broadcast address (1) or the
781            * 0's broadcast address (0).
782            */
783           bcast = getInterfaceBCastAddrByName(ifr->ifr_name);
784           (*ppIpAddrTable)->table[i].dwBCastAddr =
785            (bcast & (*ppIpAddrTable)->table[i].dwMask) ? 1 : 0;
786           /* FIXME: hardcoded reasm size, not sure where to get it */
787           (*ppIpAddrTable)->table[i].dwReasmSize = 65535;
788
789           (*ppIpAddrTable)->table[i].unused1 = 0;
790           (*ppIpAddrTable)->table[i].wType = 0;
791           i++;
792         }
793       }
794       else
795         ret = ERROR_OUTOFMEMORY;
796       HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
797     }
798   }
799   return ret;
800 }
801
802 char *toIPAddressString(unsigned int addr, char string[16])
803 {
804   if (string) {
805     struct in_addr iAddr;
806
807     iAddr.s_addr = addr;
808     /* extra-anal, just to make auditors happy */
809     lstrcpynA(string, inet_ntoa(iAddr), 16);
810   }
811   return string;
812 }