dmsynth: Dump data passed to Download method.
[wine] / dlls / iphlpapi / ifenum.c
1 /* Copyright (C) 2003,2006,2011 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
18 #include "config.h"
19
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_PARAM_H
31 #include <sys/param.h>
32 #endif
33
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
41
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
44 #endif
45
46 #ifdef HAVE_NET_IF_H
47 #include <net/if.h>
48 #endif
49
50 #ifdef HAVE_NET_IF_ARP_H
51 #include <net/if_arp.h>
52 #endif
53
54 #ifdef HAVE_NET_ROUTE_H
55 #include <net/route.h>
56 #endif
57
58 #ifdef HAVE_SYS_IOCTL_H
59 #include <sys/ioctl.h>
60 #endif
61
62 #ifdef HAVE_SYS_SYSCTL_H
63 #include <sys/sysctl.h>
64 #endif
65
66 #ifdef HAVE_SYS_SOCKIO_H
67 #include <sys/sockio.h>
68 #endif
69
70 #ifdef HAVE_NET_IF_DL_H
71 #include <net/if_dl.h>
72 #endif
73
74 #ifdef HAVE_NET_IF_TYPES_H
75 #include <net/if_types.h>
76 #endif
77
78 #ifdef HAVE_IFADDRS_H
79 #include <ifaddrs.h>
80 #endif
81
82 #include "ifenum.h"
83 #include "ws2ipdef.h"
84
85 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
86 #define ifreq_len(ifr) \
87  max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
88 #else
89 #define ifreq_len(ifr) sizeof(struct ifreq)
90 #endif
91
92 #ifndef ETH_ALEN
93 #define ETH_ALEN 6
94 #endif
95
96 #ifndef IF_NAMESIZE
97 #define IF_NAMESIZE 16
98 #endif
99
100 #ifndef INADDR_NONE
101 #define INADDR_NONE (~0U)
102 #endif
103
104 #define INITIAL_INTERFACES_ASSUMED 4
105
106 /* Functions */
107
108 static int isLoopbackInterface(int fd, const char *name)
109 {
110   int ret = 0;
111
112   if (name) {
113     struct ifreq ifr;
114
115     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
116     if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
117       ret = ifr.ifr_flags & IFF_LOOPBACK;
118   }
119   return ret;
120 }
121
122 /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
123  * bytes are necessary.
124  */
125 char *getInterfaceNameByIndex(IF_INDEX index, char *name)
126 {
127   return if_indextoname(index, name);
128 }
129
130 DWORD getInterfaceIndexByName(const char *name, IF_INDEX *index)
131 {
132   DWORD ret;
133   unsigned int idx;
134
135   if (!name)
136     return ERROR_INVALID_PARAMETER;
137   if (!index)
138     return ERROR_INVALID_PARAMETER;
139   idx = if_nametoindex(name);
140   if (idx) {
141     *index = idx;
142     ret = NO_ERROR;
143   }
144   else
145     ret = ERROR_INVALID_DATA;
146   return ret;
147 }
148
149 BOOL isIfIndexLoopback(ULONG idx)
150 {
151   BOOL ret = FALSE;
152   char name[IFNAMSIZ];
153   int fd;
154
155   getInterfaceNameByIndex(idx, name);
156   fd = socket(PF_INET, SOCK_DGRAM, 0);
157   if (fd != -1) {
158     ret = isLoopbackInterface(fd, name);
159     close(fd);
160   }
161   return ret;
162 }
163
164 DWORD getNumNonLoopbackInterfaces(void)
165 {
166   DWORD numInterfaces;
167   int fd = socket(PF_INET, SOCK_DGRAM, 0);
168
169   if (fd != -1) {
170     struct if_nameindex *indexes = if_nameindex();
171
172     if (indexes) {
173       struct if_nameindex *p;
174
175       for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
176         if (!isLoopbackInterface(fd, p->if_name))
177           numInterfaces++;
178       if_freenameindex(indexes);
179     }
180     else
181       numInterfaces = 0;
182     close(fd);
183   }
184   else
185     numInterfaces = 0;
186   return numInterfaces;
187 }
188
189 DWORD getNumInterfaces(void)
190 {
191   DWORD numInterfaces;
192   struct if_nameindex *indexes = if_nameindex();
193
194   if (indexes) {
195     struct if_nameindex *p;
196
197     for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
198       numInterfaces++;
199     if_freenameindex(indexes);
200   }
201   else
202     numInterfaces = 0;
203   return numInterfaces;
204 }
205
206 InterfaceIndexTable *getInterfaceIndexTable(void)
207 {
208   DWORD numInterfaces;
209   InterfaceIndexTable *ret;
210   struct if_nameindex *indexes = if_nameindex();
211
212   if (indexes) {
213     struct if_nameindex *p;
214
215     for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
216       numInterfaces++;
217     ret = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable, indexes[numInterfaces]));
218     if (ret) {
219       ret->numIndexes = 0;
220       for (p = indexes; p && p->if_name; p++)
221         ret->indexes[ret->numIndexes++] = p->if_index;
222     }
223     if_freenameindex(indexes);
224   }
225   else
226     ret = NULL;
227   return ret;
228 }
229
230 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
231 {
232   DWORD numInterfaces;
233   InterfaceIndexTable *ret;
234   int fd = socket(PF_INET, SOCK_DGRAM, 0);
235
236   if (fd != -1) {
237     struct if_nameindex *indexes = if_nameindex();
238
239     if (indexes) {
240       struct if_nameindex *p;
241
242       for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
243         if (!isLoopbackInterface(fd, p->if_name))
244           numInterfaces++;
245       ret = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable, indexes[numInterfaces]));
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) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
302 static 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 static 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 static 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   unsigned 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(IF_INDEX 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 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 DWORD getInterfaceStatusByName(const char *name, INTERNAL_IF_OPER_STATUS *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 static DWORD getIPAddrRowByName(PMIB_IPADDRROW ipAddrRow, const char *ifName,
656  const struct sockaddr *sa)
657 {
658   DWORD ret, bcast;
659
660   ret = getInterfaceIndexByName(ifName, &ipAddrRow->dwIndex);
661   memcpy(&ipAddrRow->dwAddr, sa->sa_data + 2, sizeof(DWORD));
662   ipAddrRow->dwMask = getInterfaceMaskByName(ifName);
663   /* the dwBCastAddr member isn't the broadcast address, it indicates whether
664    * the interface uses the 1's broadcast address (1) or the 0's broadcast
665    * address (0).
666    */
667   bcast = getInterfaceBCastAddrByName(ifName);
668   ipAddrRow->dwBCastAddr = (bcast & ipAddrRow->dwMask) ? 1 : 0;
669   /* FIXME: hardcoded reasm size, not sure where to get it */
670   ipAddrRow->dwReasmSize = 65535;
671   ipAddrRow->unused1 = 0;
672   ipAddrRow->wType = 0;
673   return ret;
674 }
675
676 #ifdef HAVE_IFADDRS_H
677
678 /* Counts the IPv4 addresses in the system using the return value from
679  * getifaddrs, returning the count.
680  */
681 static DWORD countIPv4Addresses(struct ifaddrs *ifa)
682 {
683   DWORD numAddresses = 0;
684
685   for (; ifa; ifa = ifa->ifa_next)
686     if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET)
687       numAddresses++;
688   return numAddresses;
689 }
690
691 DWORD getNumIPAddresses(void)
692 {
693   DWORD numAddresses = 0;
694   struct ifaddrs *ifa;
695
696   if (!getifaddrs(&ifa))
697   {
698     numAddresses = countIPv4Addresses(ifa);
699     freeifaddrs(ifa);
700   }
701   return numAddresses;
702 }
703
704 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
705 {
706   DWORD ret;
707
708   if (!ppIpAddrTable)
709     ret = ERROR_INVALID_PARAMETER;
710   else
711   {
712     struct ifaddrs *ifa;
713
714     if (!getifaddrs(&ifa))
715     {
716       DWORD size = sizeof(MIB_IPADDRTABLE);
717       DWORD numAddresses = countIPv4Addresses(ifa);
718
719       if (numAddresses > 1)
720         size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
721       *ppIpAddrTable = HeapAlloc(heap, flags, size);
722       if (*ppIpAddrTable)
723       {
724         DWORD i = 0;
725         struct ifaddrs *ifp;
726
727         ret = NO_ERROR;
728         (*ppIpAddrTable)->dwNumEntries = numAddresses;
729         for (ifp = ifa; !ret && ifp; ifp = ifp->ifa_next)
730         {
731           if (!ifp->ifa_addr || ifp->ifa_addr->sa_family != AF_INET)
732             continue;
733
734           ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifp->ifa_name,
735            ifp->ifa_addr);
736           i++;
737         }
738         if (ret)
739           HeapFree(GetProcessHeap(), 0, *ppIpAddrTable);
740       }
741       else
742         ret = ERROR_OUTOFMEMORY;
743       freeifaddrs(ifa);
744     }
745     else
746       ret = ERROR_INVALID_PARAMETER;
747   }
748   return ret;
749 }
750
751 ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
752 {
753   struct ifaddrs *ifa;
754   ULONG ret;
755
756   if (!getifaddrs(&ifa))
757   {
758     struct ifaddrs *p;
759     ULONG n;
760     char name[IFNAMSIZ];
761
762     getInterfaceNameByIndex(index, name);
763     for (p = ifa, n = 0; p; p = p->ifa_next)
764       if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
765           !strcmp(name, p->ifa_name))
766         n++;
767     if (n)
768     {
769       *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
770                          sizeof(struct WS_sockaddr_in6)));
771       if (*addrs)
772       {
773         struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
774             (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
775
776         for (p = ifa, n = 0; p; p = p->ifa_next)
777         {
778           if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
779               !strcmp(name, p->ifa_name))
780           {
781             struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
782
783             next_addr->sin6_family = WS_AF_INET6;
784             next_addr->sin6_port = addr->sin6_port;
785             next_addr->sin6_flowinfo = addr->sin6_flowinfo;
786             memcpy(&next_addr->sin6_addr, &addr->sin6_addr,
787              sizeof(next_addr->sin6_addr));
788             next_addr->sin6_scope_id = addr->sin6_scope_id;
789             (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
790             (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
791             next_addr++;
792             n++;
793           }
794         }
795         *num_addrs = n;
796         ret = ERROR_SUCCESS;
797       }
798       else
799         ret = ERROR_OUTOFMEMORY;
800     }
801     else
802     {
803       *addrs = NULL;
804       *num_addrs = 0;
805       ret = ERROR_SUCCESS;
806     }
807     freeifaddrs(ifa);
808   }
809   else
810     ret = ERROR_NO_DATA;
811   return ret;
812 }
813
814 #else
815
816 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
817  * the count to you in *pcAddresses.  It also returns to you the struct ifconf
818  * used by the call to ioctl, so that you may process the addresses further.
819  * Free ifc->ifc_buf using HeapFree.
820  * Returns NO_ERROR on success, something else on failure.
821  */
822 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
823 {
824   DWORD ret;
825   int fd;
826
827   fd = socket(PF_INET, SOCK_DGRAM, 0);
828   if (fd != -1) {
829     int ioctlRet = 0;
830     DWORD guessedNumAddresses = 0, numAddresses = 0;
831     caddr_t ifPtr;
832     int lastlen;
833
834     ret = NO_ERROR;
835     ifc->ifc_len = 0;
836     ifc->ifc_buf = NULL;
837     /* there is no way to know the interface count beforehand,
838        so we need to loop again and again upping our max each time
839        until returned is constant across 2 calls */
840     do {
841       lastlen = ifc->ifc_len;
842       HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
843       if (guessedNumAddresses == 0)
844         guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
845       else
846         guessedNumAddresses *= 2;
847       ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
848       ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
849       ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
850     } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
851
852     if (ioctlRet == 0) {
853       ifPtr = ifc->ifc_buf;
854       while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
855         struct ifreq *ifr = (struct ifreq *)ifPtr;
856
857         if (ifr->ifr_addr.sa_family == AF_INET)
858           numAddresses++;
859
860         ifPtr += ifreq_len((struct ifreq *)ifPtr);
861       }
862     }
863     else
864       ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
865     if (!ret)
866       *pcAddresses = numAddresses;
867     else
868     {
869       HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
870       ifc->ifc_buf = NULL;
871     }
872     close(fd);
873   }
874   else
875     ret = ERROR_NO_SYSTEM_RESOURCES;
876   return ret;
877 }
878
879 DWORD getNumIPAddresses(void)
880 {
881   DWORD numAddresses = 0;
882   struct ifconf ifc;
883
884   if (!enumIPAddresses(&numAddresses, &ifc))
885     HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
886   return numAddresses;
887 }
888
889 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
890 {
891   DWORD ret;
892
893   if (!ppIpAddrTable)
894     ret = ERROR_INVALID_PARAMETER;
895   else
896   {
897     DWORD numAddresses = 0;
898     struct ifconf ifc;
899
900     ret = enumIPAddresses(&numAddresses, &ifc);
901     if (!ret)
902     {
903       DWORD size = sizeof(MIB_IPADDRTABLE);
904
905       if (numAddresses > 1)
906         size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
907       *ppIpAddrTable = HeapAlloc(heap, flags, size);
908       if (*ppIpAddrTable) {
909         DWORD i = 0;
910         caddr_t ifPtr;
911
912         ret = NO_ERROR;
913         (*ppIpAddrTable)->dwNumEntries = numAddresses;
914         ifPtr = ifc.ifc_buf;
915         while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
916           struct ifreq *ifr = (struct ifreq *)ifPtr;
917
918           ifPtr += ifreq_len(ifr);
919
920           if (ifr->ifr_addr.sa_family != AF_INET)
921              continue;
922
923           ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifr->ifr_name,
924            &ifr->ifr_addr);
925           i++;
926         }
927         if (ret)
928           HeapFree(GetProcessHeap(), 0, *ppIpAddrTable);
929       }
930       else
931         ret = ERROR_OUTOFMEMORY;
932       HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
933     }
934   }
935   return ret;
936 }
937
938 ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
939 {
940   *addrs = NULL;
941   *num_addrs = 0;
942   return ERROR_SUCCESS;
943 }
944
945 #endif
946
947 char *toIPAddressString(unsigned int addr, char string[16])
948 {
949   if (string) {
950     struct in_addr iAddr;
951
952     iAddr.s_addr = addr;
953     /* extra-anal, just to make auditors happy */
954     lstrcpynA(string, inet_ntoa(iAddr), 16);
955   }
956   return string;
957 }