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