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