schannel: Use FIELD_OFFSET instead of offsetof.
[wine] / dlls / iphlpapi / ifenum.c
1 /* Copyright (C) 2003,2006 Juan Lang
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2.1 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16  *
17  * Implementation notes
18  * FIXME:
19  * - I don't support IPv6 addresses here, since SIOCGIFCONF can't return them
20  *
21  * There are three implemented methods for determining the MAC address of an
22  * interface:
23  * - a specific IOCTL (Linux)
24  * - looking in the ARP cache (at least Solaris)
25  * - using the sysctl interface (FreeBSD and Mac OS X)
26  * Solaris and some others have SIOCGENADDR, but I haven't gotten that to work
27  * on the Solaris boxes at SourceForge's compile farm, whereas SIOCGARP does.
28  */
29
30 #include "config.h"
31
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #include <sys/types.h>
42 #ifdef HAVE_SYS_PARAM_H
43 #include <sys/param.h>
44 #endif
45
46 #ifdef HAVE_SYS_SOCKET_H
47 #include <sys/socket.h>
48 #endif
49
50 #ifdef HAVE_NETINET_IN_H
51 #include <netinet/in.h>
52 #endif
53
54 #ifdef HAVE_ARPA_INET_H
55 #include <arpa/inet.h>
56 #endif
57
58 #ifdef HAVE_NET_IF_H
59 #include <net/if.h>
60 #endif
61
62 #ifdef HAVE_NET_IF_ARP_H
63 #include <net/if_arp.h>
64 #endif
65
66 #ifdef HAVE_NET_ROUTE_H
67 #include <net/route.h>
68 #endif
69
70 #ifdef HAVE_SYS_IOCTL_H
71 #include <sys/ioctl.h>
72 #endif
73
74 #ifdef HAVE_SYS_SYSCTL_H
75 #include <sys/sysctl.h>
76 #endif
77
78 #ifdef HAVE_SYS_SOCKIO_H
79 #include <sys/sockio.h>
80 #endif
81
82 #ifdef HAVE_NET_IF_DL_H
83 #include <net/if_dl.h>
84 #endif
85
86 #ifdef HAVE_NET_IF_TYPES_H
87 #include <net/if_types.h>
88 #endif
89
90 #include "ifenum.h"
91
92 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
93 #define ifreq_len(ifr) \
94  max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
95 #else
96 #define ifreq_len(ifr) sizeof(struct ifreq)
97 #endif
98
99 #ifndef ETH_ALEN
100 #define ETH_ALEN 6
101 #endif
102
103 #ifndef IF_NAMESIZE
104 #define IF_NAMESIZE 16
105 #endif
106
107 #ifndef INADDR_NONE
108 #define INADDR_NONE (~0U)
109 #endif
110
111 #define INITIAL_INTERFACES_ASSUMED 4
112
113 #define INDEX_IS_LOOPBACK 0x00800000
114
115 /* Functions */
116
117 static int isLoopbackInterface(int fd, const char *name)
118 {
119   int ret = 0;
120
121   if (name) {
122     struct ifreq ifr;
123
124     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
125     if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
126       ret = ifr.ifr_flags & IFF_LOOPBACK;
127   }
128   return ret;
129 }
130
131 /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
132  * bytes are necessary.
133  */
134 char *getInterfaceNameByIndex(DWORD index, char *name)
135 {
136   return if_indextoname(index, name);
137 }
138
139 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
140 {
141   DWORD ret;
142   unsigned int idx;
143
144   if (!name)
145     return ERROR_INVALID_PARAMETER;
146   if (!index)
147     return ERROR_INVALID_PARAMETER;
148   idx = if_nametoindex(name);
149   if (idx) {
150     *index = idx;
151     ret = NO_ERROR;
152   }
153   else
154     ret = ERROR_INVALID_DATA;
155   return ret;
156 }
157
158 DWORD getNumNonLoopbackInterfaces(void)
159 {
160   DWORD numInterfaces;
161   int fd = socket(PF_INET, SOCK_DGRAM, 0);
162
163   if (fd != -1) {
164     struct if_nameindex *indexes = if_nameindex();
165
166     if (indexes) {
167       struct if_nameindex *p;
168
169       for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
170         if (!isLoopbackInterface(fd, p->if_name))
171           numInterfaces++;
172       if_freenameindex(indexes);
173     }
174     else
175       numInterfaces = 0;
176     close(fd);
177   }
178   else
179     numInterfaces = 0;
180   return numInterfaces;
181 }
182
183 DWORD getNumInterfaces(void)
184 {
185   DWORD numInterfaces;
186   struct if_nameindex *indexes = if_nameindex();
187
188   if (indexes) {
189     struct if_nameindex *p;
190
191     for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
192       numInterfaces++;
193     if_freenameindex(indexes);
194   }
195   else
196     numInterfaces = 0;
197   return numInterfaces;
198 }
199
200 InterfaceIndexTable *getInterfaceIndexTable(void)
201 {
202   DWORD numInterfaces;
203   InterfaceIndexTable *ret;
204   struct if_nameindex *indexes = if_nameindex();
205
206   if (indexes) {
207     struct if_nameindex *p;
208
209     for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
210       numInterfaces++;
211     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
212      sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
213     if (ret) {
214       for (p = indexes; p && p->if_name; p++)
215         ret->indexes[ret->numIndexes++] = p->if_index;
216     }
217     if_freenameindex(indexes);
218   }
219   else
220     ret = NULL;
221   return ret;
222 }
223
224 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
225 {
226   DWORD numInterfaces;
227   InterfaceIndexTable *ret;
228   int fd = socket(PF_INET, SOCK_DGRAM, 0);
229
230   if (fd != -1) {
231     struct if_nameindex *indexes = if_nameindex();
232
233     if (indexes) {
234       struct if_nameindex *p;
235
236       for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
237         if (!isLoopbackInterface(fd, p->if_name))
238           numInterfaces++;
239       ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
240        sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
241       if (ret) {
242         for (p = indexes; p && p->if_name; p++)
243           if (!isLoopbackInterface(fd, p->if_name))
244             ret->indexes[ret->numIndexes++] = p->if_index;
245       }
246       if_freenameindex(indexes);
247     }
248     else
249       ret = NULL;
250     close(fd);
251   }
252   else
253     ret = NULL;
254   return ret;
255 }
256
257 static DWORD getInterfaceBCastAddrByName(const char *name)
258 {
259   DWORD ret = INADDR_ANY;
260
261   if (name) {
262     int fd = socket(PF_INET, SOCK_DGRAM, 0);
263
264     if (fd != -1) {
265       struct ifreq ifr;
266
267       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
268       if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
269         memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
270       close(fd);
271     }
272   }
273   return ret;
274 }
275
276 static DWORD getInterfaceMaskByName(const char *name)
277 {
278   DWORD ret = INADDR_NONE;
279
280   if (name) {
281     int fd = socket(PF_INET, SOCK_DGRAM, 0);
282
283     if (fd != -1) {
284       struct ifreq ifr;
285
286       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
287       if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
288         memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
289       close(fd);
290     }
291   }
292   return ret;
293 }
294
295 #if defined (SIOCGIFHWADDR)
296 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
297  PDWORD type)
298 {
299   DWORD ret;
300   int fd;
301
302   if (!name || !len || !addr || !type)
303     return ERROR_INVALID_PARAMETER;
304
305   fd = socket(PF_INET, SOCK_DGRAM, 0);
306   if (fd != -1) {
307     struct ifreq ifr;
308
309     memset(&ifr, 0, sizeof(struct ifreq));
310     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
311     if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
312       ret = ERROR_INVALID_DATA;
313     else {
314       unsigned int addrLen;
315
316       switch (ifr.ifr_hwaddr.sa_family)
317       {
318 #ifdef ARPHRD_LOOPBACK
319         case ARPHRD_LOOPBACK:
320           addrLen = 0;
321           *type = MIB_IF_TYPE_LOOPBACK;
322           break;
323 #endif
324 #ifdef ARPHRD_ETHER
325         case ARPHRD_ETHER:
326           addrLen = ETH_ALEN;
327           *type = MIB_IF_TYPE_ETHERNET;
328           break;
329 #endif
330 #ifdef ARPHRD_FDDI
331         case ARPHRD_FDDI:
332           addrLen = ETH_ALEN;
333           *type = MIB_IF_TYPE_FDDI;
334           break;
335 #endif
336 #ifdef ARPHRD_IEEE802
337         case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
338           addrLen = ETH_ALEN;
339           *type = MIB_IF_TYPE_TOKENRING;
340           break;
341 #endif
342 #ifdef ARPHRD_IEEE802_TR
343         case ARPHRD_IEEE802_TR: /* also Token Ring? */
344           addrLen = ETH_ALEN;
345           *type = MIB_IF_TYPE_TOKENRING;
346           break;
347 #endif
348 #ifdef ARPHRD_SLIP
349         case ARPHRD_SLIP:
350           addrLen = 0;
351           *type = MIB_IF_TYPE_SLIP;
352           break;
353 #endif
354 #ifdef ARPHRD_PPP
355         case ARPHRD_PPP:
356           addrLen = 0;
357           *type = MIB_IF_TYPE_PPP;
358           break;
359 #endif
360         default:
361           addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
362           *type = MIB_IF_TYPE_OTHER;
363       }
364       if (addrLen > *len) {
365         ret = ERROR_INSUFFICIENT_BUFFER;
366         *len = addrLen;
367       }
368       else {
369         if (addrLen > 0)
370           memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
371         /* zero out remaining bytes for broken implementations */
372         memset(addr + addrLen, 0, *len - addrLen);
373         *len = addrLen;
374         ret = NO_ERROR;
375       }
376     }
377     close(fd);
378   }
379   else
380     ret = ERROR_NO_MORE_FILES;
381   return ret;
382 }
383 #elif defined (SIOCGARP)
384 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
385  PDWORD type)
386 {
387   DWORD ret;
388   int fd;
389
390   if (!name || !len || !addr || !type)
391     return ERROR_INVALID_PARAMETER;
392
393   fd = socket(PF_INET, SOCK_DGRAM, 0);
394   if (fd != -1) {
395     if (isLoopbackInterface(fd, name)) {
396       *type = MIB_IF_TYPE_LOOPBACK;
397       memset(addr, 0, *len);
398       *len = 0;
399       ret=NOERROR;
400     }
401     else {
402       struct arpreq arp;
403       struct sockaddr_in *saddr;
404       struct ifreq ifr;
405
406       /* get IP addr */
407       lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
408       ioctl(fd, SIOCGIFADDR, &ifr);
409       memset(&arp, 0, sizeof(struct arpreq));
410       arp.arp_pa.sa_family = AF_INET;
411       saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
412       saddr->sin_family = AF_INET;
413       memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
414       if ((ioctl(fd, SIOCGARP, &arp)))
415         ret = ERROR_INVALID_DATA;
416       else {
417         /* FIXME:  heh:  who said it was ethernet? */
418         int addrLen = ETH_ALEN;
419
420         if (addrLen > *len) {
421           ret = ERROR_INSUFFICIENT_BUFFER;
422           *len = addrLen;
423         }
424         else {
425           if (addrLen > 0)
426             memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
427           /* zero out remaining bytes for broken implementations */
428           memset(addr + addrLen, 0, *len - addrLen);
429           *len = addrLen;
430           *type = MIB_IF_TYPE_ETHERNET;
431           ret = NO_ERROR;
432         }
433       }
434     }
435     close(fd);
436   }
437     else
438       ret = ERROR_NO_MORE_FILES;
439
440   return ret;
441 }
442 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
443 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
444  PDWORD type)
445 {
446   DWORD ret;
447   struct if_msghdr *ifm;
448   struct sockaddr_dl *sdl;
449   u_char *p, *buf;
450   size_t mibLen;
451   int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
452   int addrLen;
453   BOOL found = FALSE;
454
455   if (!name || !len || !addr || !type)
456     return ERROR_INVALID_PARAMETER;
457
458   if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
459     return ERROR_NO_MORE_FILES;
460
461   buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
462   if (!buf)
463     return ERROR_NOT_ENOUGH_MEMORY;
464
465   if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
466     HeapFree(GetProcessHeap(), 0, buf);
467     return ERROR_NO_MORE_FILES;
468   }
469
470   ret = ERROR_INVALID_DATA;
471   for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
472     ifm = (struct if_msghdr *)p;
473     sdl = (struct sockaddr_dl *)(ifm + 1);
474
475     if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
476       continue;
477
478     if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
479      memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
480       continue;
481
482     found = TRUE;
483     addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
484     if (addrLen > *len) {
485       ret = ERROR_INSUFFICIENT_BUFFER;
486       *len = addrLen;
487     }
488     else {
489       if (addrLen > 0)
490         memcpy(addr, LLADDR(sdl), addrLen);
491       /* zero out remaining bytes for broken implementations */
492       memset(addr + addrLen, 0, *len - addrLen);
493       *len = addrLen;
494 #if defined(HAVE_NET_IF_TYPES_H)
495       switch (sdl->sdl_type)
496       {
497         case IFT_ETHER:
498           *type = MIB_IF_TYPE_ETHERNET;
499           break;
500         case IFT_FDDI:
501           *type = MIB_IF_TYPE_FDDI;
502           break;
503         case IFT_ISO88024: /* Token Bus */
504           *type = MIB_IF_TYPE_TOKENRING;
505           break;
506         case IFT_ISO88025: /* Token Ring */
507           *type = MIB_IF_TYPE_TOKENRING;
508           break;
509         case IFT_PPP:
510           *type = MIB_IF_TYPE_PPP;
511           break;
512         case IFT_SLIP:
513           *type = MIB_IF_TYPE_SLIP;
514           break;
515         case IFT_LOOP:
516           *type = MIB_IF_TYPE_LOOPBACK;
517           break;
518         default:
519           *type = MIB_IF_TYPE_OTHER;
520       }
521 #else
522       /* default if we don't know */
523       *type = MIB_IF_TYPE_ETHERNET;
524 #endif
525       ret = NO_ERROR;
526     }
527   }
528   HeapFree(GetProcessHeap(), 0, buf);
529   return ret;
530 }
531 #endif
532
533 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
534  PDWORD type)
535 {
536   char nameBuf[IF_NAMESIZE];
537   char *name = getInterfaceNameByIndex(index, nameBuf);
538
539   if (name)
540     return getInterfacePhysicalByName(name, len, addr, type);
541   else
542     return ERROR_INVALID_DATA;
543 }
544
545 static DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
546 {
547   DWORD ret;
548   int fd;
549
550   if (!name)
551     return ERROR_INVALID_PARAMETER;
552   if (!mtu)
553     return ERROR_INVALID_PARAMETER;
554
555   fd = socket(PF_INET, SOCK_DGRAM, 0);
556   if (fd != -1) {
557     struct ifreq ifr;
558
559     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
560     if ((ioctl(fd, SIOCGIFMTU, &ifr)))
561       ret = ERROR_INVALID_DATA;
562     else {
563 #ifndef __sun
564       *mtu = ifr.ifr_mtu;
565 #else
566       *mtu = ifr.ifr_metric;
567 #endif
568       ret = NO_ERROR;
569     }
570     close(fd);
571   }
572   else
573     ret = ERROR_NO_MORE_FILES;
574   return ret;
575 }
576
577 static DWORD getInterfaceStatusByName(const char *name, PDWORD status)
578 {
579   DWORD ret;
580   int fd;
581
582   if (!name)
583     return ERROR_INVALID_PARAMETER;
584   if (!status)
585     return ERROR_INVALID_PARAMETER;
586
587   fd = socket(PF_INET, SOCK_DGRAM, 0);
588   if (fd != -1) {
589     struct ifreq ifr;
590
591     lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
592     if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
593       ret = ERROR_INVALID_DATA;
594     else {
595       if (ifr.ifr_flags & IFF_UP)
596         *status = MIB_IF_OPER_STATUS_OPERATIONAL;
597       else
598         *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
599       ret = NO_ERROR;
600     }
601     close(fd);
602   }
603   else
604     ret = ERROR_NO_MORE_FILES;
605   return ret;
606 }
607
608 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
609 {
610   BYTE addr[MAX_INTERFACE_PHYSADDR];
611   DWORD ret, len = sizeof(addr), type;
612
613   if (!name)
614     return ERROR_INVALID_PARAMETER;
615   if (!entry)
616     return ERROR_INVALID_PARAMETER;
617
618   if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
619     WCHAR *assigner;
620     const char *walker;
621
622     memset(entry, 0, sizeof(MIB_IFROW));
623     for (assigner = entry->wszName, walker = name; *walker; 
624      walker++, assigner++)
625       *assigner = *walker;
626     *assigner = 0;
627     getInterfaceIndexByName(name, &entry->dwIndex);
628     entry->dwPhysAddrLen = len;
629     memcpy(entry->bPhysAddr, addr, len);
630     memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
631     entry->dwType = type;
632     /* FIXME: how to calculate real speed? */
633     getInterfaceMtuByName(name, &entry->dwMtu);
634     /* lie, there's no "administratively down" here */
635     entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
636     getInterfaceStatusByName(name, &entry->dwOperStatus);
637     /* punt on dwLastChange? */
638     entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
639     memcpy(entry->bDescr, name, entry->dwDescrLen);
640     entry->bDescr[entry->dwDescrLen] = '\0';
641     entry->dwDescrLen++;
642     ret = NO_ERROR;
643   }
644   else
645     ret = ERROR_INVALID_DATA;
646   return ret;
647 }
648
649 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
650 {
651   char nameBuf[IF_NAMESIZE];
652   char *name = getInterfaceNameByIndex(index, nameBuf);
653
654   if (name)
655     return getInterfaceEntryByName(name, entry);
656   else
657     return ERROR_INVALID_DATA;
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       *ppIpAddrTable = HeapAlloc(heap, flags, sizeof(MIB_IPADDRTABLE) +
748        (numAddresses - 1) * sizeof(MIB_IPADDRROW));
749       if (*ppIpAddrTable) {
750         DWORD i = 0, bcast;
751         caddr_t ifPtr;
752
753         ret = NO_ERROR;
754         (*ppIpAddrTable)->dwNumEntries = numAddresses;
755         ifPtr = ifc.ifc_buf;
756         while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
757           struct ifreq *ifr = (struct ifreq *)ifPtr;
758
759           ifPtr += ifreq_len(ifr);
760
761           if (ifr->ifr_addr.sa_family != AF_INET)
762              continue;
763
764           ret = getInterfaceIndexByName(ifr->ifr_name,
765            &(*ppIpAddrTable)->table[i].dwIndex);
766           memcpy(&(*ppIpAddrTable)->table[i].dwAddr, ifr->ifr_addr.sa_data + 2,
767            sizeof(DWORD));
768           (*ppIpAddrTable)->table[i].dwMask =
769            getInterfaceMaskByName(ifr->ifr_name);
770           /* the dwBCastAddr member isn't the broadcast address, it indicates
771            * whether the interface uses the 1's broadcast address (1) or the
772            * 0's broadcast address (0).
773            */
774           bcast = getInterfaceBCastAddrByName(ifr->ifr_name);
775           (*ppIpAddrTable)->table[i].dwBCastAddr =
776            (bcast & (*ppIpAddrTable)->table[i].dwMask) ? 1 : 0;
777           /* FIXME: hardcoded reasm size, not sure where to get it */
778           (*ppIpAddrTable)->table[i].dwReasmSize = 65535;
779
780           (*ppIpAddrTable)->table[i].unused1 = 0;
781           (*ppIpAddrTable)->table[i].wType = 0;
782           i++;
783         }
784       }
785       else
786         ret = ERROR_OUTOFMEMORY;
787       HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
788     }
789   }
790   return ret;
791 }
792
793 char *toIPAddressString(unsigned int addr, char string[16])
794 {
795   if (string) {
796     struct in_addr iAddr;
797
798     iAddr.s_addr = addr;
799     /* extra-anal, just to make auditors happy */
800     lstrcpynA(string, inet_ntoa(iAddr), 16);
801   }
802   return string;
803 }