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