include: Add the missing inaddr.h and in6addr.h include directives.
[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(DWORD index, char *name)
126 {
127   return if_indextoname(index, name);
128 }
129
130 DWORD getInterfaceIndexByName(const char *name, PDWORD 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     DWORD size = sizeof(InterfaceIndexTable);
215
216     for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
217       numInterfaces++;
218     if (numInterfaces > 1)
219       size += (numInterfaces - 1) * sizeof(DWORD);
220     ret = HeapAlloc(GetProcessHeap(), 0, size);
221     if (ret) {
222       ret->numIndexes = 0;
223       for (p = indexes; p && p->if_name; p++)
224         ret->indexes[ret->numIndexes++] = p->if_index;
225     }
226     if_freenameindex(indexes);
227   }
228   else
229     ret = NULL;
230   return ret;
231 }
232
233 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
234 {
235   DWORD numInterfaces;
236   InterfaceIndexTable *ret;
237   int fd = socket(PF_INET, SOCK_DGRAM, 0);
238
239   if (fd != -1) {
240     struct if_nameindex *indexes = if_nameindex();
241
242     if (indexes) {
243       struct if_nameindex *p;
244       DWORD size = sizeof(InterfaceIndexTable);
245
246       for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
247         if (!isLoopbackInterface(fd, p->if_name))
248           numInterfaces++;
249       if (numInterfaces > 1)
250         size += (numInterfaces - 1) * sizeof(DWORD);
251       ret = HeapAlloc(GetProcessHeap(), 0, size);
252       if (ret) {
253         ret->numIndexes = 0;
254         for (p = indexes; p && p->if_name; p++)
255           if (!isLoopbackInterface(fd, p->if_name))
256             ret->indexes[ret->numIndexes++] = p->if_index;
257       }
258       if_freenameindex(indexes);
259     }
260     else
261       ret = NULL;
262     close(fd);
263   }
264   else
265     ret = NULL;
266   return ret;
267 }
268
269 static DWORD getInterfaceBCastAddrByName(const char *name)
270 {
271   DWORD ret = INADDR_ANY;
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, SIOCGIFBRDADDR, &ifr) == 0)
281         memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
282       close(fd);
283     }
284   }
285   return ret;
286 }
287
288 static DWORD getInterfaceMaskByName(const char *name)
289 {
290   DWORD ret = INADDR_NONE;
291
292   if (name) {
293     int fd = socket(PF_INET, SOCK_DGRAM, 0);
294
295     if (fd != -1) {
296       struct ifreq ifr;
297
298       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
299       if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
300         memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
301       close(fd);
302     }
303   }
304   return ret;
305 }
306
307 #if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
308 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
309  PDWORD type)
310 {
311   DWORD ret;
312   int fd;
313
314   if (!name || !len || !addr || !type)
315     return ERROR_INVALID_PARAMETER;
316
317   fd = socket(PF_INET, SOCK_DGRAM, 0);
318   if (fd != -1) {
319     struct ifreq ifr;
320
321     memset(&ifr, 0, sizeof(struct ifreq));
322     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
323     if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
324       ret = ERROR_INVALID_DATA;
325     else {
326       unsigned int addrLen;
327
328       switch (ifr.ifr_hwaddr.sa_family)
329       {
330 #ifdef ARPHRD_LOOPBACK
331         case ARPHRD_LOOPBACK:
332           addrLen = 0;
333           *type = MIB_IF_TYPE_LOOPBACK;
334           break;
335 #endif
336 #ifdef ARPHRD_ETHER
337         case ARPHRD_ETHER:
338           addrLen = ETH_ALEN;
339           *type = MIB_IF_TYPE_ETHERNET;
340           break;
341 #endif
342 #ifdef ARPHRD_FDDI
343         case ARPHRD_FDDI:
344           addrLen = ETH_ALEN;
345           *type = MIB_IF_TYPE_FDDI;
346           break;
347 #endif
348 #ifdef ARPHRD_IEEE802
349         case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
350           addrLen = ETH_ALEN;
351           *type = MIB_IF_TYPE_TOKENRING;
352           break;
353 #endif
354 #ifdef ARPHRD_IEEE802_TR
355         case ARPHRD_IEEE802_TR: /* also Token Ring? */
356           addrLen = ETH_ALEN;
357           *type = MIB_IF_TYPE_TOKENRING;
358           break;
359 #endif
360 #ifdef ARPHRD_SLIP
361         case ARPHRD_SLIP:
362           addrLen = 0;
363           *type = MIB_IF_TYPE_SLIP;
364           break;
365 #endif
366 #ifdef ARPHRD_PPP
367         case ARPHRD_PPP:
368           addrLen = 0;
369           *type = MIB_IF_TYPE_PPP;
370           break;
371 #endif
372         default:
373           addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
374           *type = MIB_IF_TYPE_OTHER;
375       }
376       if (addrLen > *len) {
377         ret = ERROR_INSUFFICIENT_BUFFER;
378         *len = addrLen;
379       }
380       else {
381         if (addrLen > 0)
382           memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
383         /* zero out remaining bytes for broken implementations */
384         memset(addr + addrLen, 0, *len - addrLen);
385         *len = addrLen;
386         ret = NO_ERROR;
387       }
388     }
389     close(fd);
390   }
391   else
392     ret = ERROR_NO_MORE_FILES;
393   return ret;
394 }
395 #elif defined (SIOCGARP)
396 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
397  PDWORD type)
398 {
399   DWORD ret;
400   int fd;
401
402   if (!name || !len || !addr || !type)
403     return ERROR_INVALID_PARAMETER;
404
405   fd = socket(PF_INET, SOCK_DGRAM, 0);
406   if (fd != -1) {
407     if (isLoopbackInterface(fd, name)) {
408       *type = MIB_IF_TYPE_LOOPBACK;
409       memset(addr, 0, *len);
410       *len = 0;
411       ret=NOERROR;
412     }
413     else {
414       struct arpreq arp;
415       struct sockaddr_in *saddr;
416       struct ifreq ifr;
417
418       /* get IP addr */
419       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
420       ioctl(fd, SIOCGIFADDR, &ifr);
421       memset(&arp, 0, sizeof(struct arpreq));
422       arp.arp_pa.sa_family = AF_INET;
423       saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
424       saddr->sin_family = AF_INET;
425       memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
426       if ((ioctl(fd, SIOCGARP, &arp)))
427         ret = ERROR_INVALID_DATA;
428       else {
429         /* FIXME:  heh:  who said it was ethernet? */
430         int addrLen = ETH_ALEN;
431
432         if (addrLen > *len) {
433           ret = ERROR_INSUFFICIENT_BUFFER;
434           *len = addrLen;
435         }
436         else {
437           if (addrLen > 0)
438             memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
439           /* zero out remaining bytes for broken implementations */
440           memset(addr + addrLen, 0, *len - addrLen);
441           *len = addrLen;
442           *type = MIB_IF_TYPE_ETHERNET;
443           ret = NO_ERROR;
444         }
445       }
446     }
447     close(fd);
448   }
449     else
450       ret = ERROR_NO_MORE_FILES;
451
452   return ret;
453 }
454 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
455 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
456  PDWORD type)
457 {
458   DWORD ret;
459   struct if_msghdr *ifm;
460   struct sockaddr_dl *sdl;
461   u_char *p, *buf;
462   size_t mibLen;
463   int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
464   unsigned addrLen;
465   BOOL found = FALSE;
466
467   if (!name || !len || !addr || !type)
468     return ERROR_INVALID_PARAMETER;
469
470   if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
471     return ERROR_NO_MORE_FILES;
472
473   buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
474   if (!buf)
475     return ERROR_NOT_ENOUGH_MEMORY;
476
477   if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
478     HeapFree(GetProcessHeap(), 0, buf);
479     return ERROR_NO_MORE_FILES;
480   }
481
482   ret = ERROR_INVALID_DATA;
483   for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
484     ifm = (struct if_msghdr *)p;
485     sdl = (struct sockaddr_dl *)(ifm + 1);
486
487     if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
488       continue;
489
490     if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
491      memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
492       continue;
493
494     found = TRUE;
495     addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
496     if (addrLen > *len) {
497       ret = ERROR_INSUFFICIENT_BUFFER;
498       *len = addrLen;
499     }
500     else {
501       if (addrLen > 0)
502         memcpy(addr, LLADDR(sdl), addrLen);
503       /* zero out remaining bytes for broken implementations */
504       memset(addr + addrLen, 0, *len - addrLen);
505       *len = addrLen;
506 #if defined(HAVE_NET_IF_TYPES_H)
507       switch (sdl->sdl_type)
508       {
509         case IFT_ETHER:
510           *type = MIB_IF_TYPE_ETHERNET;
511           break;
512         case IFT_FDDI:
513           *type = MIB_IF_TYPE_FDDI;
514           break;
515         case IFT_ISO88024: /* Token Bus */
516           *type = MIB_IF_TYPE_TOKENRING;
517           break;
518         case IFT_ISO88025: /* Token Ring */
519           *type = MIB_IF_TYPE_TOKENRING;
520           break;
521         case IFT_PPP:
522           *type = MIB_IF_TYPE_PPP;
523           break;
524         case IFT_SLIP:
525           *type = MIB_IF_TYPE_SLIP;
526           break;
527         case IFT_LOOP:
528           *type = MIB_IF_TYPE_LOOPBACK;
529           break;
530         default:
531           *type = MIB_IF_TYPE_OTHER;
532       }
533 #else
534       /* default if we don't know */
535       *type = MIB_IF_TYPE_ETHERNET;
536 #endif
537       ret = NO_ERROR;
538     }
539   }
540   HeapFree(GetProcessHeap(), 0, buf);
541   return ret;
542 }
543 #endif
544
545 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
546  PDWORD type)
547 {
548   char nameBuf[IF_NAMESIZE];
549   char *name = getInterfaceNameByIndex(index, nameBuf);
550
551   if (name)
552     return getInterfacePhysicalByName(name, len, addr, type);
553   else
554     return ERROR_INVALID_DATA;
555 }
556
557 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
558 {
559   DWORD ret;
560   int fd;
561
562   if (!name)
563     return ERROR_INVALID_PARAMETER;
564   if (!mtu)
565     return ERROR_INVALID_PARAMETER;
566
567   fd = socket(PF_INET, SOCK_DGRAM, 0);
568   if (fd != -1) {
569     struct ifreq ifr;
570
571     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
572     if ((ioctl(fd, SIOCGIFMTU, &ifr)))
573       ret = ERROR_INVALID_DATA;
574     else {
575 #ifndef __sun
576       *mtu = ifr.ifr_mtu;
577 #else
578       *mtu = ifr.ifr_metric;
579 #endif
580       ret = NO_ERROR;
581     }
582     close(fd);
583   }
584   else
585     ret = ERROR_NO_MORE_FILES;
586   return ret;
587 }
588
589 DWORD getInterfaceStatusByName(const char *name, PDWORD status)
590 {
591   DWORD ret;
592   int fd;
593
594   if (!name)
595     return ERROR_INVALID_PARAMETER;
596   if (!status)
597     return ERROR_INVALID_PARAMETER;
598
599   fd = socket(PF_INET, SOCK_DGRAM, 0);
600   if (fd != -1) {
601     struct ifreq ifr;
602
603     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
604     if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
605       ret = ERROR_INVALID_DATA;
606     else {
607       if (ifr.ifr_flags & IFF_UP)
608         *status = MIB_IF_OPER_STATUS_OPERATIONAL;
609       else
610         *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
611       ret = NO_ERROR;
612     }
613     close(fd);
614   }
615   else
616     ret = ERROR_NO_MORE_FILES;
617   return ret;
618 }
619
620 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
621 {
622   BYTE addr[MAX_INTERFACE_PHYSADDR];
623   DWORD ret, len = sizeof(addr), type;
624
625   if (!name)
626     return ERROR_INVALID_PARAMETER;
627   if (!entry)
628     return ERROR_INVALID_PARAMETER;
629
630   if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
631     WCHAR *assigner;
632     const char *walker;
633
634     memset(entry, 0, sizeof(MIB_IFROW));
635     for (assigner = entry->wszName, walker = name; *walker; 
636      walker++, assigner++)
637       *assigner = *walker;
638     *assigner = 0;
639     getInterfaceIndexByName(name, &entry->dwIndex);
640     entry->dwPhysAddrLen = len;
641     memcpy(entry->bPhysAddr, addr, len);
642     memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
643     entry->dwType = type;
644     /* FIXME: how to calculate real speed? */
645     getInterfaceMtuByName(name, &entry->dwMtu);
646     /* lie, there's no "administratively down" here */
647     entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
648     getInterfaceStatusByName(name, &entry->dwOperStatus);
649     /* punt on dwLastChange? */
650     entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
651     memcpy(entry->bDescr, name, entry->dwDescrLen);
652     entry->bDescr[entry->dwDescrLen] = '\0';
653     entry->dwDescrLen++;
654     ret = NO_ERROR;
655   }
656   else
657     ret = ERROR_INVALID_DATA;
658   return ret;
659 }
660
661 static DWORD getIPAddrRowByName(PMIB_IPADDRROW ipAddrRow, const char *ifName,
662  const struct sockaddr *sa)
663 {
664   DWORD ret, bcast;
665
666   ret = getInterfaceIndexByName(ifName, &ipAddrRow->dwIndex);
667   memcpy(&ipAddrRow->dwAddr, sa->sa_data + 2, sizeof(DWORD));
668   ipAddrRow->dwMask = getInterfaceMaskByName(ifName);
669   /* the dwBCastAddr member isn't the broadcast address, it indicates whether
670    * the interface uses the 1's broadcast address (1) or the 0's broadcast
671    * address (0).
672    */
673   bcast = getInterfaceBCastAddrByName(ifName);
674   ipAddrRow->dwBCastAddr = (bcast & ipAddrRow->dwMask) ? 1 : 0;
675   /* FIXME: hardcoded reasm size, not sure where to get it */
676   ipAddrRow->dwReasmSize = 65535;
677   ipAddrRow->unused1 = 0;
678   ipAddrRow->wType = 0;
679   return ret;
680 }
681
682 #ifdef HAVE_IFADDRS_H
683
684 /* Counts the IPv4 addresses in the system using the return value from
685  * getifaddrs, returning the count.
686  */
687 static DWORD countIPv4Addresses(struct ifaddrs *ifa)
688 {
689   DWORD numAddresses = 0;
690
691   for (; ifa; ifa = ifa->ifa_next)
692     if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET)
693       numAddresses++;
694   return numAddresses;
695 }
696
697 DWORD getNumIPAddresses(void)
698 {
699   DWORD numAddresses = 0;
700   struct ifaddrs *ifa;
701
702   if (!getifaddrs(&ifa))
703   {
704     numAddresses = countIPv4Addresses(ifa);
705     freeifaddrs(ifa);
706   }
707   return numAddresses;
708 }
709
710 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
711 {
712   DWORD ret;
713
714   if (!ppIpAddrTable)
715     ret = ERROR_INVALID_PARAMETER;
716   else
717   {
718     struct ifaddrs *ifa;
719
720     if (!getifaddrs(&ifa))
721     {
722       DWORD size = sizeof(MIB_IPADDRTABLE);
723       DWORD numAddresses = countIPv4Addresses(ifa);
724
725       if (numAddresses > 1)
726         size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
727       *ppIpAddrTable = HeapAlloc(heap, flags, size);
728       if (*ppIpAddrTable)
729       {
730         DWORD i = 0;
731         struct ifaddrs *ifp;
732
733         ret = NO_ERROR;
734         (*ppIpAddrTable)->dwNumEntries = numAddresses;
735         for (ifp = ifa; !ret && ifp; ifp = ifp->ifa_next)
736         {
737           if (!ifp->ifa_addr || ifp->ifa_addr->sa_family != AF_INET)
738             continue;
739
740           ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifp->ifa_name,
741            ifp->ifa_addr);
742           i++;
743         }
744       }
745       else
746         ret = ERROR_OUTOFMEMORY;
747       freeifaddrs(ifa);
748     }
749     else
750       ret = ERROR_INVALID_PARAMETER;
751   }
752   return ret;
753 }
754
755 ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
756 {
757   struct ifaddrs *ifa;
758   ULONG ret;
759
760   if (!getifaddrs(&ifa))
761   {
762     struct ifaddrs *p;
763     ULONG n;
764     char name[IFNAMSIZ];
765
766     getInterfaceNameByIndex(index, name);
767     for (p = ifa, n = 0; p; p = p->ifa_next)
768       if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
769           !strcmp(name, p->ifa_name))
770         n++;
771     if (n)
772     {
773       *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
774                          sizeof(struct WS_sockaddr_in6)));
775       if (*addrs)
776       {
777         struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
778             (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
779
780         for (p = ifa, n = 0; p; p = p->ifa_next)
781         {
782           if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
783               !strcmp(name, p->ifa_name))
784           {
785             struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
786
787             next_addr->sin6_family = WS_AF_INET6;
788             next_addr->sin6_port = addr->sin6_port;
789             next_addr->sin6_flowinfo = addr->sin6_flowinfo;
790             memcpy(&next_addr->sin6_addr, &addr->sin6_addr,
791              sizeof(next_addr->sin6_addr));
792             next_addr->sin6_scope_id = addr->sin6_scope_id;
793             (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
794             (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
795             next_addr++;
796             n++;
797           }
798         }
799         *num_addrs = n;
800         ret = ERROR_SUCCESS;
801       }
802       else
803         ret = ERROR_OUTOFMEMORY;
804     }
805     else
806     {
807       *addrs = NULL;
808       *num_addrs = 0;
809       ret = ERROR_SUCCESS;
810     }
811     freeifaddrs(ifa);
812   }
813   else
814     ret = ERROR_NO_DATA;
815   return ret;
816 }
817
818 #else
819
820 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
821  * the count to you in *pcAddresses.  It also returns to you the struct ifconf
822  * used by the call to ioctl, so that you may process the addresses further.
823  * Free ifc->ifc_buf using HeapFree.
824  * Returns NO_ERROR on success, something else on failure.
825  */
826 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
827 {
828   DWORD ret;
829   int fd;
830
831   fd = socket(PF_INET, SOCK_DGRAM, 0);
832   if (fd != -1) {
833     int ioctlRet = 0;
834     DWORD guessedNumAddresses = 0, numAddresses = 0;
835     caddr_t ifPtr;
836     int lastlen;
837
838     ret = NO_ERROR;
839     ifc->ifc_len = 0;
840     ifc->ifc_buf = NULL;
841     /* there is no way to know the interface count beforehand,
842        so we need to loop again and again upping our max each time
843        until returned is constant across 2 calls */
844     do {
845       lastlen = ifc->ifc_len;
846       HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
847       if (guessedNumAddresses == 0)
848         guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
849       else
850         guessedNumAddresses *= 2;
851       ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
852       ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
853       ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
854     } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
855
856     if (ioctlRet == 0) {
857       ifPtr = ifc->ifc_buf;
858       while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
859         struct ifreq *ifr = (struct ifreq *)ifPtr;
860
861         if (ifr->ifr_addr.sa_family == AF_INET)
862           numAddresses++;
863
864         ifPtr += ifreq_len((struct ifreq *)ifPtr);
865       }
866     }
867     else
868       ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
869     if (!ret)
870       *pcAddresses = numAddresses;
871     else
872     {
873       HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
874       ifc->ifc_buf = NULL;
875     }
876     close(fd);
877   }
878   else
879     ret = ERROR_NO_SYSTEM_RESOURCES;
880   return ret;
881 }
882
883 DWORD getNumIPAddresses(void)
884 {
885   DWORD numAddresses = 0;
886   struct ifconf ifc;
887
888   if (!enumIPAddresses(&numAddresses, &ifc))
889     HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
890   return numAddresses;
891 }
892
893 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
894 {
895   DWORD ret;
896
897   if (!ppIpAddrTable)
898     ret = ERROR_INVALID_PARAMETER;
899   else
900   {
901     DWORD numAddresses = 0;
902     struct ifconf ifc;
903
904     ret = enumIPAddresses(&numAddresses, &ifc);
905     if (!ret)
906     {
907       DWORD size = sizeof(MIB_IPADDRTABLE);
908
909       if (numAddresses > 1)
910         size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
911       *ppIpAddrTable = HeapAlloc(heap, flags, size);
912       if (*ppIpAddrTable) {
913         DWORD i = 0;
914         caddr_t ifPtr;
915
916         ret = NO_ERROR;
917         (*ppIpAddrTable)->dwNumEntries = numAddresses;
918         ifPtr = ifc.ifc_buf;
919         while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
920           struct ifreq *ifr = (struct ifreq *)ifPtr;
921
922           ifPtr += ifreq_len(ifr);
923
924           if (ifr->ifr_addr.sa_family != AF_INET)
925              continue;
926
927           ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifr->ifr_name,
928            &ifr->ifr_addr);
929           i++;
930         }
931       }
932       else
933         ret = ERROR_OUTOFMEMORY;
934       HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
935     }
936   }
937   return ret;
938 }
939
940 ULONG v6addressesFromIndex(DWORD index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
941 {
942   *addrs = NULL;
943   *num_addrs = 0;
944   return ERROR_SUCCESS;
945 }
946
947 #endif
948
949 char *toIPAddressString(unsigned int addr, char string[16])
950 {
951   if (string) {
952     struct in_addr iAddr;
953
954     iAddr.s_addr = addr;
955     /* extra-anal, just to make auditors happy */
956     lstrcpynA(string, inet_ntoa(iAddr), 16);
957   }
958   return string;
959 }