kernel32/nls: Added LOCALE_SNAN entries.
[wine.git] / dlls / iphlpapi / ifenum.c
blobeed1be15d19585686b13a9cb02840d071e6b4a52
1 /* Copyright (C) 2003,2006,2011 Juan Lang
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.
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.
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
18 #include "config.h"
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_PARAM_H
31 #include <sys/param.h>
32 #endif
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
44 #endif
46 #ifdef HAVE_NET_IF_H
47 #include <net/if.h>
48 #endif
50 #ifdef HAVE_NET_IF_ARP_H
51 #include <net/if_arp.h>
52 #endif
54 #ifdef HAVE_NET_ROUTE_H
55 #include <net/route.h>
56 #endif
58 #ifdef HAVE_SYS_IOCTL_H
59 #include <sys/ioctl.h>
60 #endif
62 #ifdef HAVE_SYS_SYSCTL_H
63 #include <sys/sysctl.h>
64 #endif
66 #ifdef HAVE_SYS_SOCKIO_H
67 #include <sys/sockio.h>
68 #endif
70 #ifdef HAVE_NET_IF_DL_H
71 #include <net/if_dl.h>
72 #endif
74 #ifdef HAVE_NET_IF_TYPES_H
75 #include <net/if_types.h>
76 #endif
78 #ifdef HAVE_IFADDRS_H
79 #include <ifaddrs.h>
80 #endif
82 #ifdef HAVE_LINUX_RTNETLINK_H
83 #include <linux/rtnetlink.h>
84 #endif
86 #include "ifenum.h"
87 #include "ws2ipdef.h"
89 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
90 #define ifreq_len(ifr) \
91 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
92 #else
93 #define ifreq_len(ifr) sizeof(struct ifreq)
94 #endif
96 #ifndef ETH_ALEN
97 #define ETH_ALEN 6
98 #endif
100 #ifndef IF_NAMESIZE
101 #define IF_NAMESIZE 16
102 #endif
104 #ifndef INADDR_NONE
105 #define INADDR_NONE (~0U)
106 #endif
108 #define INITIAL_INTERFACES_ASSUMED 4
110 /* Functions */
112 static BOOL isLoopbackInterface(int fd, const char *name)
114 BOOL ret = FALSE;
116 if (name) {
117 struct ifreq ifr;
119 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
120 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
121 ret = ifr.ifr_flags & IFF_LOOPBACK;
123 return !!ret;
126 /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
127 * bytes are necessary.
129 char *getInterfaceNameByIndex(IF_INDEX index, char *name)
131 return if_indextoname(index, name);
134 DWORD getInterfaceIndexByName(const char *name, IF_INDEX *index)
136 DWORD ret;
137 unsigned int idx;
139 if (!name)
140 return ERROR_INVALID_PARAMETER;
141 if (!index)
142 return ERROR_INVALID_PARAMETER;
143 idx = if_nametoindex(name);
144 if (idx) {
145 *index = idx;
146 ret = NO_ERROR;
148 else
149 ret = ERROR_INVALID_DATA;
150 return ret;
153 BOOL isIfIndexLoopback(ULONG idx)
155 BOOL ret = FALSE;
156 char name[IFNAMSIZ];
157 int fd;
159 getInterfaceNameByIndex(idx, name);
160 fd = socket(PF_INET, SOCK_DGRAM, 0);
161 if (fd != -1) {
162 ret = isLoopbackInterface(fd, name);
163 close(fd);
165 return ret;
168 #ifdef HAVE_IF_NAMEINDEX
169 DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
171 DWORD count = 0, i;
172 struct if_nameindex *p, *indices = if_nameindex();
173 InterfaceIndexTable *ret;
175 if (table) *table = NULL;
176 if (!indices) return 0;
178 for (p = indices; p->if_name; p++)
180 if (skip_loopback && isIfIndexLoopback( p->if_index )) continue;
181 count++;
184 if (table)
186 ret = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable, indexes[count]) );
187 if (!ret)
189 count = 0;
190 goto end;
192 for (p = indices, i = 0; p->if_name && i < count; p++)
194 if (skip_loopback && isIfIndexLoopback( p->if_index )) continue;
195 ret->indexes[i++] = p->if_index;
197 ret->numIndexes = count = i;
198 *table = ret;
201 end:
202 if_freenameindex( indices );
203 return count;
206 #elif defined(HAVE_LINUX_RTNETLINK_H)
207 static int open_netlink( int *pid )
209 int fd = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE );
210 struct sockaddr_nl addr;
211 socklen_t len;
213 if (fd < 0) return fd;
215 memset( &addr, 0, sizeof(addr) );
216 addr.nl_family = AF_NETLINK;
218 if (bind( fd, (struct sockaddr *)&addr, sizeof(addr) ) < 0)
219 goto fail;
221 len = sizeof(addr);
222 if (getsockname( fd, (struct sockaddr *)&addr, &len ) < 0)
223 goto fail;
225 *pid = addr.nl_pid;
226 return fd;
227 fail:
228 close( fd );
229 return -1;
232 static int send_netlink_req( int fd, int pid, int type, int *seq_no )
234 static LONG seq;
235 struct request
237 struct nlmsghdr hdr;
238 struct rtgenmsg gen;
239 } req;
240 struct sockaddr_nl addr;
242 req.hdr.nlmsg_len = sizeof(req);
243 req.hdr.nlmsg_type = type;
244 req.hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
245 req.hdr.nlmsg_pid = pid;
246 req.hdr.nlmsg_seq = InterlockedIncrement( &seq );
247 req.gen.rtgen_family = AF_UNSPEC;
249 memset( &addr, 0, sizeof(addr) );
250 addr.nl_family = AF_NETLINK;
251 if (sendto( fd, &req, sizeof(req), 0, (struct sockaddr *)&addr, sizeof(addr) ) != sizeof(req))
252 return -1;
253 *seq_no = req.hdr.nlmsg_seq;
254 return 0;
257 struct netlink_reply
259 struct netlink_reply *next;
260 int size;
261 struct nlmsghdr *hdr;
264 static void free_netlink_reply( struct netlink_reply *data )
266 struct netlink_reply *ptr;
267 while( data )
269 ptr = data->next;
270 HeapFree( GetProcessHeap(), 0, data );
271 data = ptr;
275 static int recv_netlink_reply( int fd, int pid, int seq, struct netlink_reply **data )
277 int bufsize = getpagesize();
278 int left, read;
279 BOOL done = FALSE;
280 socklen_t sa_len;
281 struct sockaddr_nl addr;
282 struct netlink_reply *cur, *last = NULL;
283 struct nlmsghdr *hdr;
284 char *buf;
286 *data = NULL;
287 buf = HeapAlloc( GetProcessHeap(), 0, bufsize );
288 if (!buf) return -1;
292 left = read = recvfrom( fd, buf, bufsize, 0, (struct sockaddr *)&addr, &sa_len );
293 if (read < 0) goto fail;
294 if (addr.nl_pid != 0) continue; /* not from kernel */
296 for (hdr = (struct nlmsghdr *)buf; NLMSG_OK(hdr, left); hdr = NLMSG_NEXT(hdr, left))
298 if (hdr->nlmsg_pid != pid || hdr->nlmsg_seq != seq) continue;
299 if (hdr->nlmsg_type == NLMSG_DONE)
301 done = TRUE;
302 break;
306 cur = HeapAlloc( GetProcessHeap(), 0, sizeof(*cur) + read );
307 if (!cur) goto fail;
308 cur->next = NULL;
309 cur->size = read;
310 cur->hdr = (struct nlmsghdr *)(cur + 1);
311 memcpy( cur->hdr, buf, read );
312 if (last) last->next = cur;
313 else *data = cur;
314 last = cur;
315 } while (!done);
317 HeapFree( GetProcessHeap(), 0, buf );
318 return 0;
320 fail:
321 free_netlink_reply( *data );
322 HeapFree( GetProcessHeap(), 0, buf );
323 return -1;
327 static DWORD get_indices_from_reply( struct netlink_reply *reply, int pid, int seq,
328 BOOL skip_loopback, InterfaceIndexTable *table )
330 struct nlmsghdr *hdr;
331 struct netlink_reply *r;
332 int count = 0;
334 for (r = reply; r; r = r->next)
336 int size = r->size;
337 for (hdr = r->hdr; NLMSG_OK(hdr, size); hdr = NLMSG_NEXT(hdr, size))
339 if (hdr->nlmsg_pid != pid || hdr->nlmsg_seq != seq) continue;
340 if (hdr->nlmsg_type == NLMSG_DONE) break;
342 if (hdr->nlmsg_type == RTM_NEWLINK)
344 struct ifinfomsg *info = NLMSG_DATA(hdr);
346 if (skip_loopback && (info->ifi_flags & IFF_LOOPBACK)) continue;
347 if (table) table->indexes[count] = info->ifi_index;
348 count++;
352 return count;
355 DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
357 int fd, pid, seq;
358 struct netlink_reply *reply = NULL;
359 DWORD count = 0;
361 if (table) *table = NULL;
362 fd = open_netlink( &pid );
363 if (fd < 0) return 0;
365 if (send_netlink_req( fd, pid, RTM_GETLINK, &seq ) < 0)
366 goto end;
368 if (recv_netlink_reply( fd, pid, seq, &reply ) < 0)
369 goto end;
371 count = get_indices_from_reply( reply, pid, seq, skip_loopback, NULL );
373 if (table)
375 InterfaceIndexTable *ret = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable, indexes[count]) );
376 if (!ret)
378 count = 0;
379 goto end;
382 ret->numIndexes = count;
383 get_indices_from_reply( reply, pid, seq, skip_loopback, ret );
384 *table = ret;
387 end:
388 free_netlink_reply( reply );
389 close( fd );
390 return count;
393 #else
394 DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
396 if (table) *table = NULL;
397 return 0;
399 #endif
401 static DWORD getInterfaceBCastAddrByName(const char *name)
403 DWORD ret = INADDR_ANY;
405 if (name) {
406 int fd = socket(PF_INET, SOCK_DGRAM, 0);
408 if (fd != -1) {
409 struct ifreq ifr;
411 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
412 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
413 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
414 close(fd);
417 return ret;
420 static DWORD getInterfaceMaskByName(const char *name)
422 DWORD ret = INADDR_NONE;
424 if (name) {
425 int fd = socket(PF_INET, SOCK_DGRAM, 0);
427 if (fd != -1) {
428 struct ifreq ifr;
430 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
431 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
432 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
433 close(fd);
436 return ret;
439 #if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
440 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
441 PDWORD type)
443 DWORD ret;
444 int fd;
446 if (!name || !len || !addr || !type)
447 return ERROR_INVALID_PARAMETER;
449 fd = socket(PF_INET, SOCK_DGRAM, 0);
450 if (fd != -1) {
451 struct ifreq ifr;
453 memset(&ifr, 0, sizeof(struct ifreq));
454 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
455 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
456 ret = ERROR_INVALID_DATA;
457 else {
458 unsigned int addrLen;
460 switch (ifr.ifr_hwaddr.sa_family)
462 #ifdef ARPHRD_LOOPBACK
463 case ARPHRD_LOOPBACK:
464 addrLen = 0;
465 *type = MIB_IF_TYPE_LOOPBACK;
466 break;
467 #endif
468 #ifdef ARPHRD_ETHER
469 case ARPHRD_ETHER:
470 addrLen = ETH_ALEN;
471 *type = MIB_IF_TYPE_ETHERNET;
472 break;
473 #endif
474 #ifdef ARPHRD_FDDI
475 case ARPHRD_FDDI:
476 addrLen = ETH_ALEN;
477 *type = MIB_IF_TYPE_FDDI;
478 break;
479 #endif
480 #ifdef ARPHRD_IEEE802
481 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
482 addrLen = ETH_ALEN;
483 *type = MIB_IF_TYPE_TOKENRING;
484 break;
485 #endif
486 #ifdef ARPHRD_IEEE802_TR
487 case ARPHRD_IEEE802_TR: /* also Token Ring? */
488 addrLen = ETH_ALEN;
489 *type = MIB_IF_TYPE_TOKENRING;
490 break;
491 #endif
492 #ifdef ARPHRD_SLIP
493 case ARPHRD_SLIP:
494 addrLen = 0;
495 *type = MIB_IF_TYPE_SLIP;
496 break;
497 #endif
498 #ifdef ARPHRD_PPP
499 case ARPHRD_PPP:
500 addrLen = 0;
501 *type = MIB_IF_TYPE_PPP;
502 break;
503 #endif
504 default:
505 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
506 *type = MIB_IF_TYPE_OTHER;
508 if (addrLen > *len) {
509 ret = ERROR_INSUFFICIENT_BUFFER;
510 *len = addrLen;
512 else {
513 if (addrLen > 0)
514 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
515 /* zero out remaining bytes for broken implementations */
516 memset(addr + addrLen, 0, *len - addrLen);
517 *len = addrLen;
518 ret = NO_ERROR;
521 close(fd);
523 else
524 ret = ERROR_NO_MORE_FILES;
525 return ret;
527 #elif defined (SIOCGARP)
528 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
529 PDWORD type)
531 DWORD ret;
532 int fd;
534 if (!name || !len || !addr || !type)
535 return ERROR_INVALID_PARAMETER;
537 fd = socket(PF_INET, SOCK_DGRAM, 0);
538 if (fd != -1) {
539 if (isLoopbackInterface(fd, name)) {
540 *type = MIB_IF_TYPE_LOOPBACK;
541 memset(addr, 0, *len);
542 *len = 0;
543 ret=NOERROR;
545 else {
546 struct arpreq arp;
547 struct sockaddr_in *saddr;
548 struct ifreq ifr;
550 /* get IP addr */
551 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
552 ioctl(fd, SIOCGIFADDR, &ifr);
553 memset(&arp, 0, sizeof(struct arpreq));
554 arp.arp_pa.sa_family = AF_INET;
555 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
556 saddr->sin_family = AF_INET;
557 memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
558 if ((ioctl(fd, SIOCGARP, &arp)))
559 ret = ERROR_INVALID_DATA;
560 else {
561 /* FIXME: heh: who said it was ethernet? */
562 int addrLen = ETH_ALEN;
564 if (addrLen > *len) {
565 ret = ERROR_INSUFFICIENT_BUFFER;
566 *len = addrLen;
568 else {
569 if (addrLen > 0)
570 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
571 /* zero out remaining bytes for broken implementations */
572 memset(addr + addrLen, 0, *len - addrLen);
573 *len = addrLen;
574 *type = MIB_IF_TYPE_ETHERNET;
575 ret = NO_ERROR;
579 close(fd);
581 else
582 ret = ERROR_NO_MORE_FILES;
584 return ret;
586 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
587 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
588 PDWORD type)
590 DWORD ret;
591 struct if_msghdr *ifm;
592 struct sockaddr_dl *sdl;
593 u_char *p, *buf;
594 size_t mibLen;
595 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
596 unsigned addrLen;
597 BOOL found = FALSE;
599 if (!name || !len || !addr || !type)
600 return ERROR_INVALID_PARAMETER;
602 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
603 return ERROR_NO_MORE_FILES;
605 buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
606 if (!buf)
607 return ERROR_NOT_ENOUGH_MEMORY;
609 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
610 HeapFree(GetProcessHeap(), 0, buf);
611 return ERROR_NO_MORE_FILES;
614 ret = ERROR_INVALID_DATA;
615 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
616 ifm = (struct if_msghdr *)p;
617 sdl = (struct sockaddr_dl *)(ifm + 1);
619 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
620 continue;
622 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
623 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
624 continue;
626 found = TRUE;
627 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
628 if (addrLen > *len) {
629 ret = ERROR_INSUFFICIENT_BUFFER;
630 *len = addrLen;
632 else {
633 if (addrLen > 0)
634 memcpy(addr, LLADDR(sdl), addrLen);
635 /* zero out remaining bytes for broken implementations */
636 memset(addr + addrLen, 0, *len - addrLen);
637 *len = addrLen;
638 #if defined(HAVE_NET_IF_TYPES_H)
639 switch (sdl->sdl_type)
641 case IFT_ETHER:
642 *type = MIB_IF_TYPE_ETHERNET;
643 break;
644 case IFT_FDDI:
645 *type = MIB_IF_TYPE_FDDI;
646 break;
647 case IFT_ISO88024: /* Token Bus */
648 *type = MIB_IF_TYPE_TOKENRING;
649 break;
650 case IFT_ISO88025: /* Token Ring */
651 *type = MIB_IF_TYPE_TOKENRING;
652 break;
653 case IFT_PPP:
654 *type = MIB_IF_TYPE_PPP;
655 break;
656 case IFT_SLIP:
657 *type = MIB_IF_TYPE_SLIP;
658 break;
659 case IFT_LOOP:
660 *type = MIB_IF_TYPE_LOOPBACK;
661 break;
662 default:
663 *type = MIB_IF_TYPE_OTHER;
665 #else
666 /* default if we don't know */
667 *type = MIB_IF_TYPE_ETHERNET;
668 #endif
669 ret = NO_ERROR;
672 HeapFree(GetProcessHeap(), 0, buf);
673 return ret;
675 #endif
677 DWORD getInterfacePhysicalByIndex(IF_INDEX index, PDWORD len, PBYTE addr,
678 PDWORD type)
680 char nameBuf[IF_NAMESIZE];
681 char *name = getInterfaceNameByIndex(index, nameBuf);
683 if (name)
684 return getInterfacePhysicalByName(name, len, addr, type);
685 else
686 return ERROR_INVALID_DATA;
689 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
691 DWORD ret;
692 int fd;
694 if (!name)
695 return ERROR_INVALID_PARAMETER;
696 if (!mtu)
697 return ERROR_INVALID_PARAMETER;
699 fd = socket(PF_INET, SOCK_DGRAM, 0);
700 if (fd != -1) {
701 struct ifreq ifr;
703 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
704 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
705 ret = ERROR_INVALID_DATA;
706 else {
707 #ifndef __sun
708 *mtu = ifr.ifr_mtu;
709 #else
710 *mtu = ifr.ifr_metric;
711 #endif
712 ret = NO_ERROR;
714 close(fd);
716 else
717 ret = ERROR_NO_MORE_FILES;
718 return ret;
721 DWORD getInterfaceStatusByName(const char *name, INTERNAL_IF_OPER_STATUS *status)
723 DWORD ret;
724 int fd;
726 if (!name)
727 return ERROR_INVALID_PARAMETER;
728 if (!status)
729 return ERROR_INVALID_PARAMETER;
731 fd = socket(PF_INET, SOCK_DGRAM, 0);
732 if (fd != -1) {
733 struct ifreq ifr;
735 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
736 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
737 ret = ERROR_INVALID_DATA;
738 else {
739 if (ifr.ifr_flags & IFF_UP)
740 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
741 else
742 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
743 ret = NO_ERROR;
745 close(fd);
747 else
748 ret = ERROR_NO_MORE_FILES;
749 return ret;
752 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
754 BYTE addr[MAX_INTERFACE_PHYSADDR];
755 DWORD ret, len = sizeof(addr), type;
757 if (!name)
758 return ERROR_INVALID_PARAMETER;
759 if (!entry)
760 return ERROR_INVALID_PARAMETER;
762 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
763 WCHAR *assigner;
764 const char *walker;
766 memset(entry, 0, sizeof(MIB_IFROW));
767 for (assigner = entry->wszName, walker = name; *walker;
768 walker++, assigner++)
769 *assigner = *walker;
770 *assigner = 0;
771 getInterfaceIndexByName(name, &entry->dwIndex);
772 entry->dwPhysAddrLen = len;
773 memcpy(entry->bPhysAddr, addr, len);
774 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
775 entry->dwType = type;
776 /* FIXME: how to calculate real speed? */
777 getInterfaceMtuByName(name, &entry->dwMtu);
778 /* lie, there's no "administratively down" here */
779 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
780 getInterfaceStatusByName(name, &entry->dwOperStatus);
781 /* punt on dwLastChange? */
782 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
783 memcpy(entry->bDescr, name, entry->dwDescrLen);
784 entry->bDescr[entry->dwDescrLen] = '\0';
785 entry->dwDescrLen++;
786 ret = NO_ERROR;
788 else
789 ret = ERROR_INVALID_DATA;
790 return ret;
793 static DWORD getIPAddrRowByName(PMIB_IPADDRROW ipAddrRow, const char *ifName,
794 const struct sockaddr *sa)
796 DWORD ret, bcast;
798 ret = getInterfaceIndexByName(ifName, &ipAddrRow->dwIndex);
799 memcpy(&ipAddrRow->dwAddr, sa->sa_data + 2, sizeof(DWORD));
800 ipAddrRow->dwMask = getInterfaceMaskByName(ifName);
801 /* the dwBCastAddr member isn't the broadcast address, it indicates whether
802 * the interface uses the 1's broadcast address (1) or the 0's broadcast
803 * address (0).
805 bcast = getInterfaceBCastAddrByName(ifName);
806 ipAddrRow->dwBCastAddr = (bcast & ipAddrRow->dwMask) ? 1 : 0;
807 /* FIXME: hardcoded reasm size, not sure where to get it */
808 ipAddrRow->dwReasmSize = 65535;
809 ipAddrRow->unused1 = 0;
810 /* wType is a bit field composed of MIB_IPADDR_* flags. Windows <= XP seems
811 * to like returning undocumented values 0x20 + 0x02 but for our current
812 * needs returning MIB_IPADDR_PRIMARY is enough.
814 ipAddrRow->wType = MIB_IPADDR_PRIMARY;
815 return ret;
818 #if defined(HAVE_IFADDRS_H) && defined(HAVE_GETIFADDRS)
820 /* Counts the IPv4 addresses in the system using the return value from
821 * getifaddrs, returning the count.
823 static DWORD countIPv4Addresses(struct ifaddrs *ifa)
825 DWORD numAddresses = 0;
827 for (; ifa; ifa = ifa->ifa_next)
828 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET)
829 numAddresses++;
830 return numAddresses;
833 DWORD getNumIPAddresses(void)
835 DWORD numAddresses = 0;
836 struct ifaddrs *ifa;
838 if (!getifaddrs(&ifa))
840 numAddresses = countIPv4Addresses(ifa);
841 freeifaddrs(ifa);
843 return numAddresses;
846 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
848 DWORD ret;
850 if (!ppIpAddrTable)
851 ret = ERROR_INVALID_PARAMETER;
852 else
854 struct ifaddrs *ifa;
856 if (!getifaddrs(&ifa))
858 DWORD size = sizeof(MIB_IPADDRTABLE);
859 DWORD numAddresses = countIPv4Addresses(ifa);
861 if (numAddresses > 1)
862 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
863 *ppIpAddrTable = HeapAlloc(heap, flags, size);
864 if (*ppIpAddrTable)
866 DWORD i = 0;
867 struct ifaddrs *ifp;
869 ret = NO_ERROR;
870 (*ppIpAddrTable)->dwNumEntries = numAddresses;
871 for (ifp = ifa; !ret && ifp; ifp = ifp->ifa_next)
873 if (!ifp->ifa_addr || ifp->ifa_addr->sa_family != AF_INET)
874 continue;
876 ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifp->ifa_name,
877 ifp->ifa_addr);
878 i++;
880 if (ret)
881 HeapFree(GetProcessHeap(), 0, *ppIpAddrTable);
883 else
884 ret = ERROR_OUTOFMEMORY;
885 freeifaddrs(ifa);
887 else
888 ret = ERROR_INVALID_PARAMETER;
890 return ret;
893 ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs, SOCKET_ADDRESS **masks)
895 struct ifaddrs *ifa;
896 ULONG ret;
898 if (!getifaddrs(&ifa))
900 struct ifaddrs *p;
901 ULONG n;
902 char name[IFNAMSIZ];
904 getInterfaceNameByIndex(index, name);
905 for (p = ifa, n = 0; p; p = p->ifa_next)
906 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
907 !strcmp(name, p->ifa_name))
908 n++;
909 if (n)
911 *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
912 sizeof(struct WS_sockaddr_in6)));
913 *masks = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
914 sizeof(struct WS_sockaddr_in6)));
915 if (*addrs && *masks)
917 struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
918 (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
919 struct WS_sockaddr_in6 *mask_addr = (struct WS_sockaddr_in6 *)(
920 (BYTE *)*masks + n * sizeof(SOCKET_ADDRESS));
922 for (p = ifa, n = 0; p; p = p->ifa_next)
924 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
925 !strcmp(name, p->ifa_name))
927 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
928 struct sockaddr_in6 *mask = (struct sockaddr_in6 *)p->ifa_netmask;
930 next_addr->sin6_family = WS_AF_INET6;
931 next_addr->sin6_port = addr->sin6_port;
932 next_addr->sin6_flowinfo = addr->sin6_flowinfo;
933 memcpy(&next_addr->sin6_addr, &addr->sin6_addr,
934 sizeof(next_addr->sin6_addr));
935 next_addr->sin6_scope_id = addr->sin6_scope_id;
936 (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
937 (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
938 next_addr++;
940 mask_addr->sin6_family = WS_AF_INET6;
941 mask_addr->sin6_port = mask->sin6_port;
942 mask_addr->sin6_flowinfo = mask->sin6_flowinfo;
943 memcpy(&mask_addr->sin6_addr, &mask->sin6_addr,
944 sizeof(mask_addr->sin6_addr));
945 mask_addr->sin6_scope_id = mask->sin6_scope_id;
946 (*masks)[n].lpSockaddr = (LPSOCKADDR)mask_addr;
947 (*masks)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
948 mask_addr++;
949 n++;
952 *num_addrs = n;
953 ret = ERROR_SUCCESS;
955 else
957 HeapFree(GetProcessHeap(), 0, *addrs);
958 HeapFree(GetProcessHeap(), 0, *masks);
959 ret = ERROR_OUTOFMEMORY;
962 else
964 *addrs = NULL;
965 *num_addrs = 0;
966 *masks = NULL;
967 ret = ERROR_SUCCESS;
969 freeifaddrs(ifa);
971 else
972 ret = ERROR_NO_DATA;
973 return ret;
976 #else
978 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
979 * the count to you in *pcAddresses. It also returns to you the struct ifconf
980 * used by the call to ioctl, so that you may process the addresses further.
981 * Free ifc->ifc_buf using HeapFree.
982 * Returns NO_ERROR on success, something else on failure.
984 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
986 DWORD ret;
987 int fd;
989 fd = socket(PF_INET, SOCK_DGRAM, 0);
990 if (fd != -1) {
991 int ioctlRet = 0;
992 DWORD guessedNumAddresses = 0, numAddresses = 0;
993 caddr_t ifPtr;
994 int lastlen;
996 ret = NO_ERROR;
997 ifc->ifc_len = 0;
998 ifc->ifc_buf = NULL;
999 /* there is no way to know the interface count beforehand,
1000 so we need to loop again and again upping our max each time
1001 until returned is constant across 2 calls */
1002 do {
1003 lastlen = ifc->ifc_len;
1004 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
1005 if (guessedNumAddresses == 0)
1006 guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
1007 else
1008 guessedNumAddresses *= 2;
1009 ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
1010 ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
1011 ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
1012 } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
1014 if (ioctlRet == 0) {
1015 ifPtr = ifc->ifc_buf;
1016 while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
1017 struct ifreq *ifr = (struct ifreq *)ifPtr;
1019 if (ifr->ifr_addr.sa_family == AF_INET)
1020 numAddresses++;
1022 ifPtr += ifreq_len((struct ifreq *)ifPtr);
1025 else
1026 ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
1027 if (!ret)
1028 *pcAddresses = numAddresses;
1029 else
1031 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
1032 ifc->ifc_buf = NULL;
1034 close(fd);
1036 else
1037 ret = ERROR_NO_SYSTEM_RESOURCES;
1038 return ret;
1041 DWORD getNumIPAddresses(void)
1043 DWORD numAddresses = 0;
1044 struct ifconf ifc;
1046 if (!enumIPAddresses(&numAddresses, &ifc))
1047 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
1048 return numAddresses;
1051 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
1053 DWORD ret;
1055 if (!ppIpAddrTable)
1056 ret = ERROR_INVALID_PARAMETER;
1057 else
1059 DWORD numAddresses = 0;
1060 struct ifconf ifc;
1062 ret = enumIPAddresses(&numAddresses, &ifc);
1063 if (!ret)
1065 DWORD size = sizeof(MIB_IPADDRTABLE);
1067 if (numAddresses > 1)
1068 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
1069 *ppIpAddrTable = HeapAlloc(heap, flags, size);
1070 if (*ppIpAddrTable) {
1071 DWORD i = 0;
1072 caddr_t ifPtr;
1074 ret = NO_ERROR;
1075 (*ppIpAddrTable)->dwNumEntries = numAddresses;
1076 ifPtr = ifc.ifc_buf;
1077 while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
1078 struct ifreq *ifr = (struct ifreq *)ifPtr;
1080 ifPtr += ifreq_len(ifr);
1082 if (ifr->ifr_addr.sa_family != AF_INET)
1083 continue;
1085 ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifr->ifr_name,
1086 &ifr->ifr_addr);
1087 i++;
1089 if (ret)
1090 HeapFree(GetProcessHeap(), 0, *ppIpAddrTable);
1092 else
1093 ret = ERROR_OUTOFMEMORY;
1094 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
1097 return ret;
1100 ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs, SOCKET_ADDRESS **masks)
1102 *addrs = NULL;
1103 *num_addrs = 0;
1104 *masks = NULL;
1105 return ERROR_SUCCESS;
1108 #endif
1110 char *toIPAddressString(unsigned int addr, char string[16])
1112 if (string) {
1113 struct in_addr iAddr;
1115 iAddr.s_addr = addr;
1116 /* extra-anal, just to make auditors happy */
1117 lstrcpynA(string, inet_ntoa(iAddr), 16);
1119 return string;