ntoskrnl.exe/tests: Add some IOCTL_HID_WRITE_REPORT tests.
[wine.git] / dlls / iphlpapi / ifenum.c
blob3b4ac775db70d74c098f8f66d8038f50b9949246
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_NET_IF_H
39 #include <net/if.h>
40 #endif
42 #ifdef HAVE_NET_IF_ARP_H
43 #include <net/if_arp.h>
44 #endif
46 #ifdef HAVE_NET_ROUTE_H
47 #include <net/route.h>
48 #endif
50 #ifdef HAVE_SYS_IOCTL_H
51 #include <sys/ioctl.h>
52 #endif
54 #ifdef HAVE_SYS_SYSCTL_H
55 #include <sys/sysctl.h>
56 #endif
58 #ifdef HAVE_SYS_SOCKIO_H
59 #include <sys/sockio.h>
60 #endif
62 #ifdef HAVE_NET_IF_DL_H
63 #include <net/if_dl.h>
64 #endif
66 #ifdef HAVE_NET_IF_TYPES_H
67 #include <net/if_types.h>
68 #endif
70 #ifdef HAVE_NETINET_IN_H
71 #include <netinet/in.h>
72 #endif
74 #ifdef HAVE_IFADDRS_H
75 #include <ifaddrs.h>
76 #endif
78 #ifdef HAVE_LINUX_RTNETLINK_H
79 #include <linux/rtnetlink.h>
80 #endif
82 #include "ifenum.h"
83 #include "ws2ipdef.h"
85 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
86 #define ifreq_len(ifr) \
87 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
88 #else
89 #define ifreq_len(ifr) sizeof(struct ifreq)
90 #endif
92 #ifndef ETH_ALEN
93 #define ETH_ALEN 6
94 #endif
96 #ifndef IF_NAMESIZE
97 #define IF_NAMESIZE 16
98 #endif
100 #ifndef INADDR_NONE
101 #define INADDR_NONE (~0U)
102 #endif
104 #define INITIAL_INTERFACES_ASSUMED 4
106 /* Functions */
108 static BOOL isLoopbackInterface(int fd, const char *name)
110 BOOL ret = FALSE;
112 if (name) {
113 struct ifreq ifr;
115 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
116 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
117 ret = ifr.ifr_flags & IFF_LOOPBACK;
119 return !!ret;
122 /* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
123 * bytes are necessary.
125 char *getInterfaceNameByIndex(IF_INDEX index, char *name)
127 return if_indextoname(index, name);
130 DWORD getInterfaceIndexByName(const char *name, IF_INDEX *index)
132 DWORD ret;
133 unsigned int idx;
135 if (!name)
136 return ERROR_INVALID_PARAMETER;
137 if (!index)
138 return ERROR_INVALID_PARAMETER;
139 idx = if_nametoindex(name);
140 if (idx) {
141 *index = idx;
142 ret = NO_ERROR;
144 else
145 ret = ERROR_INVALID_DATA;
146 return ret;
149 BOOL isIfIndexLoopback(ULONG idx)
151 BOOL ret = FALSE;
152 char name[IFNAMSIZ];
153 int fd;
155 getInterfaceNameByIndex(idx, name);
156 fd = socket(PF_INET, SOCK_DGRAM, 0);
157 if (fd != -1) {
158 ret = isLoopbackInterface(fd, name);
159 close(fd);
161 return ret;
164 #ifdef HAVE_IF_NAMEINDEX
165 DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
167 DWORD count = 0, i;
168 struct if_nameindex *p, *indices = if_nameindex();
169 InterfaceIndexTable *ret;
171 if (table) *table = NULL;
172 if (!indices) return 0;
174 for (p = indices; p->if_name; p++)
176 if (skip_loopback && isIfIndexLoopback( p->if_index )) continue;
177 count++;
180 if (table)
182 ret = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable, indexes[count]) );
183 if (!ret)
185 count = 0;
186 goto end;
188 for (p = indices, i = 0; p->if_name && i < count; p++)
190 if (skip_loopback && isIfIndexLoopback( p->if_index )) continue;
191 ret->indexes[i++] = p->if_index;
193 ret->numIndexes = count = i;
194 *table = ret;
197 end:
198 if_freenameindex( indices );
199 return count;
202 #elif defined(HAVE_LINUX_RTNETLINK_H)
203 static int open_netlink( int *pid )
205 int fd = socket( AF_NETLINK, SOCK_RAW, NETLINK_ROUTE );
206 struct sockaddr_nl addr;
207 socklen_t len;
209 if (fd < 0) return fd;
211 memset( &addr, 0, sizeof(addr) );
212 addr.nl_family = AF_NETLINK;
214 if (bind( fd, (struct sockaddr *)&addr, sizeof(addr) ) < 0)
215 goto fail;
217 len = sizeof(addr);
218 if (getsockname( fd, (struct sockaddr *)&addr, &len ) < 0)
219 goto fail;
221 *pid = addr.nl_pid;
222 return fd;
223 fail:
224 close( fd );
225 return -1;
228 static int send_netlink_req( int fd, int pid, int type, int *seq_no )
230 static LONG seq;
231 struct request
233 struct nlmsghdr hdr;
234 struct rtgenmsg gen;
235 } req;
236 struct sockaddr_nl addr;
238 req.hdr.nlmsg_len = sizeof(req);
239 req.hdr.nlmsg_type = type;
240 req.hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
241 req.hdr.nlmsg_pid = pid;
242 req.hdr.nlmsg_seq = InterlockedIncrement( &seq );
243 req.gen.rtgen_family = AF_UNSPEC;
245 memset( &addr, 0, sizeof(addr) );
246 addr.nl_family = AF_NETLINK;
247 if (sendto( fd, &req, sizeof(req), 0, (struct sockaddr *)&addr, sizeof(addr) ) != sizeof(req))
248 return -1;
249 *seq_no = req.hdr.nlmsg_seq;
250 return 0;
253 struct netlink_reply
255 struct netlink_reply *next;
256 int size;
257 struct nlmsghdr *hdr;
260 static void free_netlink_reply( struct netlink_reply *data )
262 struct netlink_reply *ptr;
263 while( data )
265 ptr = data->next;
266 HeapFree( GetProcessHeap(), 0, data );
267 data = ptr;
271 static int recv_netlink_reply( int fd, int pid, int seq, struct netlink_reply **data )
273 int bufsize = getpagesize();
274 int left, read;
275 BOOL done = FALSE;
276 socklen_t sa_len;
277 struct sockaddr_nl addr;
278 struct netlink_reply *cur, *last = NULL;
279 struct nlmsghdr *hdr;
280 char *buf;
282 *data = NULL;
283 buf = HeapAlloc( GetProcessHeap(), 0, bufsize );
284 if (!buf) return -1;
288 left = read = recvfrom( fd, buf, bufsize, 0, (struct sockaddr *)&addr, &sa_len );
289 if (read < 0) goto fail;
290 if (addr.nl_pid != 0) continue; /* not from kernel */
292 for (hdr = (struct nlmsghdr *)buf; NLMSG_OK(hdr, left); hdr = NLMSG_NEXT(hdr, left))
294 if (hdr->nlmsg_pid != pid || hdr->nlmsg_seq != seq) continue;
295 if (hdr->nlmsg_type == NLMSG_DONE)
297 done = TRUE;
298 break;
302 cur = HeapAlloc( GetProcessHeap(), 0, sizeof(*cur) + read );
303 if (!cur) goto fail;
304 cur->next = NULL;
305 cur->size = read;
306 cur->hdr = (struct nlmsghdr *)(cur + 1);
307 memcpy( cur->hdr, buf, read );
308 if (last) last->next = cur;
309 else *data = cur;
310 last = cur;
311 } while (!done);
313 HeapFree( GetProcessHeap(), 0, buf );
314 return 0;
316 fail:
317 free_netlink_reply( *data );
318 HeapFree( GetProcessHeap(), 0, buf );
319 return -1;
323 static DWORD get_indices_from_reply( struct netlink_reply *reply, int pid, int seq,
324 BOOL skip_loopback, InterfaceIndexTable *table )
326 struct nlmsghdr *hdr;
327 struct netlink_reply *r;
328 int count = 0;
330 for (r = reply; r; r = r->next)
332 int size = r->size;
333 for (hdr = r->hdr; NLMSG_OK(hdr, size); hdr = NLMSG_NEXT(hdr, size))
335 if (hdr->nlmsg_pid != pid || hdr->nlmsg_seq != seq) continue;
336 if (hdr->nlmsg_type == NLMSG_DONE) break;
338 if (hdr->nlmsg_type == RTM_NEWLINK)
340 struct ifinfomsg *info = NLMSG_DATA(hdr);
342 if (skip_loopback && (info->ifi_flags & IFF_LOOPBACK)) continue;
343 if (table) table->indexes[count] = info->ifi_index;
344 count++;
348 return count;
351 DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
353 int fd, pid, seq;
354 struct netlink_reply *reply = NULL;
355 DWORD count = 0;
357 if (table) *table = NULL;
358 fd = open_netlink( &pid );
359 if (fd < 0) return 0;
361 if (send_netlink_req( fd, pid, RTM_GETLINK, &seq ) < 0)
362 goto end;
364 if (recv_netlink_reply( fd, pid, seq, &reply ) < 0)
365 goto end;
367 count = get_indices_from_reply( reply, pid, seq, skip_loopback, NULL );
369 if (table)
371 InterfaceIndexTable *ret = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable, indexes[count]) );
372 if (!ret)
374 count = 0;
375 goto end;
378 ret->numIndexes = count;
379 get_indices_from_reply( reply, pid, seq, skip_loopback, ret );
380 *table = ret;
383 end:
384 free_netlink_reply( reply );
385 close( fd );
386 return count;
389 #else
390 DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
392 if (table) *table = NULL;
393 return 0;
395 #endif
397 static DWORD getInterfaceBCastAddrByName(const char *name)
399 DWORD ret = INADDR_ANY;
401 if (name) {
402 int fd = socket(PF_INET, SOCK_DGRAM, 0);
404 if (fd != -1) {
405 struct ifreq ifr;
407 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
408 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
409 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
410 close(fd);
413 return ret;
416 static DWORD getInterfaceMaskByName(const char *name)
418 DWORD ret = INADDR_NONE;
420 if (name) {
421 int fd = socket(PF_INET, SOCK_DGRAM, 0);
423 if (fd != -1) {
424 struct ifreq ifr;
426 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
427 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
428 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
429 close(fd);
432 return ret;
435 #if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
436 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
437 PDWORD type)
439 DWORD ret;
440 int fd;
442 if (!name || !len || !addr || !type)
443 return ERROR_INVALID_PARAMETER;
445 fd = socket(PF_INET, SOCK_DGRAM, 0);
446 if (fd != -1) {
447 struct ifreq ifr;
449 memset(&ifr, 0, sizeof(struct ifreq));
450 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
451 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
452 ret = ERROR_INVALID_DATA;
453 else {
454 unsigned int addrLen;
456 switch (ifr.ifr_hwaddr.sa_family)
458 #ifdef ARPHRD_LOOPBACK
459 case ARPHRD_LOOPBACK:
460 addrLen = 0;
461 *type = MIB_IF_TYPE_LOOPBACK;
462 break;
463 #endif
464 #ifdef ARPHRD_ETHER
465 case ARPHRD_ETHER:
466 addrLen = ETH_ALEN;
467 *type = MIB_IF_TYPE_ETHERNET;
468 break;
469 #endif
470 #ifdef ARPHRD_FDDI
471 case ARPHRD_FDDI:
472 addrLen = ETH_ALEN;
473 *type = MIB_IF_TYPE_FDDI;
474 break;
475 #endif
476 #ifdef ARPHRD_IEEE802
477 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
478 addrLen = ETH_ALEN;
479 *type = MIB_IF_TYPE_TOKENRING;
480 break;
481 #endif
482 #ifdef ARPHRD_IEEE802_TR
483 case ARPHRD_IEEE802_TR: /* also Token Ring? */
484 addrLen = ETH_ALEN;
485 *type = MIB_IF_TYPE_TOKENRING;
486 break;
487 #endif
488 #ifdef ARPHRD_SLIP
489 case ARPHRD_SLIP:
490 addrLen = 0;
491 *type = MIB_IF_TYPE_SLIP;
492 break;
493 #endif
494 #ifdef ARPHRD_PPP
495 case ARPHRD_PPP:
496 addrLen = 0;
497 *type = MIB_IF_TYPE_PPP;
498 break;
499 #endif
500 default:
501 addrLen = 0;
502 *type = MIB_IF_TYPE_OTHER;
504 if (addrLen > *len) {
505 ret = ERROR_INSUFFICIENT_BUFFER;
506 *len = addrLen;
508 else {
509 if (addrLen > 0)
510 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
511 /* zero out remaining bytes for broken implementations */
512 memset(addr + addrLen, 0, *len - addrLen);
513 *len = addrLen;
514 ret = NO_ERROR;
517 close(fd);
519 else
520 ret = ERROR_NO_MORE_FILES;
521 return ret;
523 #elif defined (SIOCGARP)
524 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
525 PDWORD type)
527 DWORD ret;
528 int fd;
530 if (!name || !len || !addr || !type)
531 return ERROR_INVALID_PARAMETER;
533 fd = socket(PF_INET, SOCK_DGRAM, 0);
534 if (fd != -1) {
535 if (isLoopbackInterface(fd, name)) {
536 *type = MIB_IF_TYPE_LOOPBACK;
537 memset(addr, 0, *len);
538 *len = 0;
539 ret=NOERROR;
541 else {
542 struct arpreq arp;
543 struct sockaddr_in *saddr;
544 struct ifreq ifr;
546 /* get IP addr */
547 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
548 ioctl(fd, SIOCGIFADDR, &ifr);
549 memset(&arp, 0, sizeof(struct arpreq));
550 arp.arp_pa.sa_family = AF_INET;
551 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
552 saddr->sin_family = AF_INET;
553 memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
554 if ((ioctl(fd, SIOCGARP, &arp)))
555 ret = ERROR_INVALID_DATA;
556 else {
557 /* FIXME: heh: who said it was ethernet? */
558 int addrLen = ETH_ALEN;
560 if (addrLen > *len) {
561 ret = ERROR_INSUFFICIENT_BUFFER;
562 *len = addrLen;
564 else {
565 if (addrLen > 0)
566 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
567 /* zero out remaining bytes for broken implementations */
568 memset(addr + addrLen, 0, *len - addrLen);
569 *len = addrLen;
570 *type = MIB_IF_TYPE_ETHERNET;
571 ret = NO_ERROR;
575 close(fd);
577 else
578 ret = ERROR_NO_MORE_FILES;
580 return ret;
582 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
583 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
584 PDWORD type)
586 DWORD ret;
587 struct if_msghdr *ifm;
588 struct sockaddr_dl *sdl;
589 u_char *p, *buf;
590 size_t mibLen;
591 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
592 unsigned addrLen;
593 BOOL found = FALSE;
595 if (!name || !len || !addr || !type)
596 return ERROR_INVALID_PARAMETER;
598 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
599 return ERROR_NO_MORE_FILES;
601 buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
602 if (!buf)
603 return ERROR_NOT_ENOUGH_MEMORY;
605 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
606 HeapFree(GetProcessHeap(), 0, buf);
607 return ERROR_NO_MORE_FILES;
610 ret = ERROR_INVALID_DATA;
611 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
612 ifm = (struct if_msghdr *)p;
613 sdl = (struct sockaddr_dl *)(ifm + 1);
615 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
616 continue;
618 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
619 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
620 continue;
622 found = TRUE;
623 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
624 if (addrLen > *len) {
625 ret = ERROR_INSUFFICIENT_BUFFER;
626 *len = addrLen;
628 else {
629 if (addrLen > 0)
630 memcpy(addr, LLADDR(sdl), addrLen);
631 /* zero out remaining bytes for broken implementations */
632 memset(addr + addrLen, 0, *len - addrLen);
633 *len = addrLen;
634 #if defined(HAVE_NET_IF_TYPES_H)
635 switch (sdl->sdl_type)
637 case IFT_ETHER:
638 *type = MIB_IF_TYPE_ETHERNET;
639 break;
640 case IFT_FDDI:
641 *type = MIB_IF_TYPE_FDDI;
642 break;
643 case IFT_ISO88024: /* Token Bus */
644 *type = MIB_IF_TYPE_TOKENRING;
645 break;
646 case IFT_ISO88025: /* Token Ring */
647 *type = MIB_IF_TYPE_TOKENRING;
648 break;
649 case IFT_PPP:
650 *type = MIB_IF_TYPE_PPP;
651 break;
652 case IFT_SLIP:
653 *type = MIB_IF_TYPE_SLIP;
654 break;
655 case IFT_LOOP:
656 *type = MIB_IF_TYPE_LOOPBACK;
657 break;
658 default:
659 *type = MIB_IF_TYPE_OTHER;
661 #else
662 /* default if we don't know */
663 *type = MIB_IF_TYPE_ETHERNET;
664 #endif
665 ret = NO_ERROR;
668 HeapFree(GetProcessHeap(), 0, buf);
669 return ret;
671 #endif
673 DWORD getInterfacePhysicalByIndex(IF_INDEX index, PDWORD len, PBYTE addr,
674 PDWORD type)
676 char nameBuf[IF_NAMESIZE];
677 char *name = getInterfaceNameByIndex(index, nameBuf);
679 if (name)
680 return getInterfacePhysicalByName(name, len, addr, type);
681 else
682 return ERROR_INVALID_DATA;
685 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
687 DWORD ret;
688 int fd;
690 if (!name)
691 return ERROR_INVALID_PARAMETER;
692 if (!mtu)
693 return ERROR_INVALID_PARAMETER;
695 fd = socket(PF_INET, SOCK_DGRAM, 0);
696 if (fd != -1) {
697 struct ifreq ifr;
699 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
700 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
701 ret = ERROR_INVALID_DATA;
702 else {
703 #ifndef __sun
704 *mtu = ifr.ifr_mtu;
705 #else
706 *mtu = ifr.ifr_metric;
707 #endif
708 ret = NO_ERROR;
710 close(fd);
712 else
713 ret = ERROR_NO_MORE_FILES;
714 return ret;
717 DWORD getInterfaceStatusByName(const char *name, INTERNAL_IF_OPER_STATUS *status)
719 DWORD ret;
720 int fd;
722 if (!name)
723 return ERROR_INVALID_PARAMETER;
724 if (!status)
725 return ERROR_INVALID_PARAMETER;
727 fd = socket(PF_INET, SOCK_DGRAM, 0);
728 if (fd != -1) {
729 struct ifreq ifr;
731 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
732 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
733 ret = ERROR_INVALID_DATA;
734 else {
735 if (ifr.ifr_flags & IFF_UP)
736 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
737 else
738 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
739 ret = NO_ERROR;
741 close(fd);
743 else
744 ret = ERROR_NO_MORE_FILES;
745 return ret;
748 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
750 BYTE addr[MAX_INTERFACE_PHYSADDR];
751 DWORD ret, len = sizeof(addr), type;
753 if (!name)
754 return ERROR_INVALID_PARAMETER;
755 if (!entry)
756 return ERROR_INVALID_PARAMETER;
758 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
759 WCHAR *assigner;
760 const char *walker;
762 memset(entry, 0, sizeof(MIB_IFROW));
763 for (assigner = entry->wszName, walker = name; *walker;
764 walker++, assigner++)
765 *assigner = *walker;
766 *assigner = 0;
767 getInterfaceIndexByName(name, &entry->dwIndex);
768 entry->dwPhysAddrLen = len;
769 memcpy(entry->bPhysAddr, addr, len);
770 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
771 entry->dwType = type;
772 /* FIXME: how to calculate real speed? */
773 getInterfaceMtuByName(name, &entry->dwMtu);
774 /* lie, there's no "administratively down" here */
775 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
776 getInterfaceStatusByName(name, &entry->dwOperStatus);
777 /* punt on dwLastChange? */
778 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
779 memcpy(entry->bDescr, name, entry->dwDescrLen);
780 entry->bDescr[entry->dwDescrLen] = '\0';
781 entry->dwDescrLen++;
782 ret = NO_ERROR;
784 else
785 ret = ERROR_INVALID_DATA;
786 return ret;
789 static DWORD getIPAddrRowByName(PMIB_IPADDRROW ipAddrRow, const char *ifName,
790 const struct sockaddr *sa)
792 DWORD ret, bcast;
794 ret = getInterfaceIndexByName(ifName, &ipAddrRow->dwIndex);
795 memcpy(&ipAddrRow->dwAddr, sa->sa_data + 2, sizeof(DWORD));
796 ipAddrRow->dwMask = getInterfaceMaskByName(ifName);
797 /* the dwBCastAddr member isn't the broadcast address, it indicates whether
798 * the interface uses the 1's broadcast address (1) or the 0's broadcast
799 * address (0).
801 bcast = getInterfaceBCastAddrByName(ifName);
802 ipAddrRow->dwBCastAddr = (bcast & ipAddrRow->dwMask) ? 1 : 0;
803 /* FIXME: hardcoded reasm size, not sure where to get it */
804 ipAddrRow->dwReasmSize = 65535;
805 ipAddrRow->unused1 = 0;
806 /* wType is a bit field composed of MIB_IPADDR_* flags. Windows <= XP seems
807 * to like returning undocumented values 0x20 + 0x02 but for our current
808 * needs returning MIB_IPADDR_PRIMARY is enough.
810 ipAddrRow->wType = MIB_IPADDR_PRIMARY;
811 return ret;
814 #if defined(HAVE_IFADDRS_H) && defined(HAVE_GETIFADDRS)
816 /* Counts the IPv4 addresses in the system using the return value from
817 * getifaddrs, returning the count.
819 static DWORD countIPv4Addresses(struct ifaddrs *ifa)
821 DWORD numAddresses = 0;
823 for (; ifa; ifa = ifa->ifa_next)
824 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET)
825 numAddresses++;
826 return numAddresses;
829 DWORD getNumIPAddresses(void)
831 DWORD numAddresses = 0;
832 struct ifaddrs *ifa;
834 if (!getifaddrs(&ifa))
836 numAddresses = countIPv4Addresses(ifa);
837 freeifaddrs(ifa);
839 return numAddresses;
842 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
844 DWORD ret;
846 if (!ppIpAddrTable)
847 ret = ERROR_INVALID_PARAMETER;
848 else
850 struct ifaddrs *ifa;
852 if (!getifaddrs(&ifa))
854 DWORD size = sizeof(MIB_IPADDRTABLE);
855 DWORD numAddresses = countIPv4Addresses(ifa);
857 if (numAddresses > 1)
858 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
859 *ppIpAddrTable = HeapAlloc(heap, flags, size);
860 if (*ppIpAddrTable)
862 DWORD i = 0;
863 struct ifaddrs *ifp;
865 ret = NO_ERROR;
866 (*ppIpAddrTable)->dwNumEntries = numAddresses;
867 for (ifp = ifa; !ret && ifp; ifp = ifp->ifa_next)
869 if (!ifp->ifa_addr || ifp->ifa_addr->sa_family != AF_INET)
870 continue;
872 ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifp->ifa_name,
873 ifp->ifa_addr);
874 i++;
876 if (ret)
877 HeapFree(GetProcessHeap(), 0, *ppIpAddrTable);
879 else
880 ret = ERROR_OUTOFMEMORY;
881 freeifaddrs(ifa);
883 else
884 ret = ERROR_INVALID_PARAMETER;
886 return ret;
889 ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs, SOCKET_ADDRESS **masks)
891 struct ifaddrs *ifa;
892 ULONG ret;
894 if (!getifaddrs(&ifa))
896 struct ifaddrs *p;
897 ULONG n;
898 char name[IFNAMSIZ];
900 getInterfaceNameByIndex(index, name);
901 for (p = ifa, n = 0; p; p = p->ifa_next)
902 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
903 !strcmp(name, p->ifa_name))
904 n++;
905 if (n)
907 *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
908 sizeof(struct WS_sockaddr_in6)));
909 *masks = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
910 sizeof(struct WS_sockaddr_in6)));
911 if (*addrs && *masks)
913 struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
914 (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
915 struct WS_sockaddr_in6 *mask_addr = (struct WS_sockaddr_in6 *)(
916 (BYTE *)*masks + n * sizeof(SOCKET_ADDRESS));
918 for (p = ifa, n = 0; p; p = p->ifa_next)
920 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
921 !strcmp(name, p->ifa_name))
923 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
924 struct sockaddr_in6 *mask = (struct sockaddr_in6 *)p->ifa_netmask;
926 next_addr->sin6_family = WS_AF_INET6;
927 next_addr->sin6_port = addr->sin6_port;
928 next_addr->sin6_flowinfo = addr->sin6_flowinfo;
929 memcpy(&next_addr->sin6_addr, &addr->sin6_addr,
930 sizeof(next_addr->sin6_addr));
931 next_addr->sin6_scope_id = addr->sin6_scope_id;
932 (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
933 (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
934 next_addr++;
936 mask_addr->sin6_family = WS_AF_INET6;
937 mask_addr->sin6_port = mask->sin6_port;
938 mask_addr->sin6_flowinfo = mask->sin6_flowinfo;
939 memcpy(&mask_addr->sin6_addr, &mask->sin6_addr,
940 sizeof(mask_addr->sin6_addr));
941 mask_addr->sin6_scope_id = mask->sin6_scope_id;
942 (*masks)[n].lpSockaddr = (LPSOCKADDR)mask_addr;
943 (*masks)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
944 mask_addr++;
945 n++;
948 *num_addrs = n;
949 ret = ERROR_SUCCESS;
951 else
953 HeapFree(GetProcessHeap(), 0, *addrs);
954 HeapFree(GetProcessHeap(), 0, *masks);
955 ret = ERROR_OUTOFMEMORY;
958 else
960 *addrs = NULL;
961 *num_addrs = 0;
962 *masks = NULL;
963 ret = ERROR_SUCCESS;
965 freeifaddrs(ifa);
967 else
968 ret = ERROR_NO_DATA;
969 return ret;
972 #else
974 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
975 * the count to you in *pcAddresses. It also returns to you the struct ifconf
976 * used by the call to ioctl, so that you may process the addresses further.
977 * Free ifc->ifc_buf using HeapFree.
978 * Returns NO_ERROR on success, something else on failure.
980 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
982 DWORD ret;
983 int fd;
985 fd = socket(PF_INET, SOCK_DGRAM, 0);
986 if (fd != -1) {
987 int ioctlRet = 0;
988 DWORD guessedNumAddresses = 0, numAddresses = 0;
989 caddr_t ifPtr;
990 int lastlen;
992 ret = NO_ERROR;
993 ifc->ifc_len = 0;
994 ifc->ifc_buf = NULL;
995 /* there is no way to know the interface count beforehand,
996 so we need to loop again and again upping our max each time
997 until returned is constant across 2 calls */
998 do {
999 lastlen = ifc->ifc_len;
1000 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
1001 if (guessedNumAddresses == 0)
1002 guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
1003 else
1004 guessedNumAddresses *= 2;
1005 ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
1006 ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
1007 ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
1008 } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
1010 if (ioctlRet == 0) {
1011 ifPtr = ifc->ifc_buf;
1012 while (ifPtr && (char *)ifPtr < ifc->ifc_buf + ifc->ifc_len) {
1013 struct ifreq *ifr = (struct ifreq *)ifPtr;
1015 if (ifr->ifr_addr.sa_family == AF_INET)
1016 numAddresses++;
1018 ifPtr = (char *)ifPtr + ifreq_len((struct ifreq *)ifPtr);
1021 else
1022 ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
1023 if (!ret)
1024 *pcAddresses = numAddresses;
1025 else
1027 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
1028 ifc->ifc_buf = NULL;
1030 close(fd);
1032 else
1033 ret = ERROR_NO_SYSTEM_RESOURCES;
1034 return ret;
1037 DWORD getNumIPAddresses(void)
1039 DWORD numAddresses = 0;
1040 struct ifconf ifc;
1042 if (!enumIPAddresses(&numAddresses, &ifc))
1043 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
1044 return numAddresses;
1047 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
1049 DWORD ret;
1051 if (!ppIpAddrTable)
1052 ret = ERROR_INVALID_PARAMETER;
1053 else
1055 DWORD numAddresses = 0;
1056 struct ifconf ifc;
1058 ret = enumIPAddresses(&numAddresses, &ifc);
1059 if (!ret)
1061 DWORD size = sizeof(MIB_IPADDRTABLE);
1063 if (numAddresses > 1)
1064 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
1065 *ppIpAddrTable = HeapAlloc(heap, flags, size);
1066 if (*ppIpAddrTable) {
1067 DWORD i = 0;
1068 caddr_t ifPtr;
1070 ret = NO_ERROR;
1071 (*ppIpAddrTable)->dwNumEntries = numAddresses;
1072 ifPtr = ifc.ifc_buf;
1073 while (!ret && ifPtr && (char *)ifPtr < ifc.ifc_buf + ifc.ifc_len) {
1074 struct ifreq *ifr = (struct ifreq *)ifPtr;
1076 ifPtr = (char *)ifPtr + ifreq_len(ifr);
1078 if (ifr->ifr_addr.sa_family != AF_INET)
1079 continue;
1081 ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifr->ifr_name,
1082 &ifr->ifr_addr);
1083 i++;
1085 if (ret)
1086 HeapFree(GetProcessHeap(), 0, *ppIpAddrTable);
1088 else
1089 ret = ERROR_OUTOFMEMORY;
1090 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
1093 return ret;
1096 ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs, SOCKET_ADDRESS **masks)
1098 *addrs = NULL;
1099 *num_addrs = 0;
1100 *masks = NULL;
1101 return ERROR_SUCCESS;
1104 #endif