mshtml: Added separated structure to store request data.
[wine/multimedia.git] / dlls / iphlpapi / ifenum.c
blob03c1b1a798f3a359d310b651a73cabe96fa60b3b
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 int isLoopbackInterface(int fd, const char *name)
114 int ret = 0;
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, done = 0;
279 socklen_t sa_len;
280 struct sockaddr_nl addr;
281 struct netlink_reply *cur, *last = NULL;
282 struct nlmsghdr *hdr;
283 char *buf;
285 *data = NULL;
286 buf = HeapAlloc( GetProcessHeap(), 0, bufsize );
287 if (!buf) return -1;
291 left = read = recvfrom( fd, buf, bufsize, 0, (struct sockaddr *)&addr, &sa_len );
292 if (read < 0) goto fail;
293 if (addr.nl_pid != 0) continue; /* not from kernel */
295 for (hdr = (struct nlmsghdr *)buf; NLMSG_OK(hdr, left); hdr = NLMSG_NEXT(hdr, left))
297 if (hdr->nlmsg_pid != pid || hdr->nlmsg_seq != seq) continue;
298 if (hdr->nlmsg_type == NLMSG_DONE)
300 done = 1;
301 break;
305 cur = HeapAlloc( GetProcessHeap(), 0, sizeof(*cur) + read );
306 if (!cur) goto fail;
307 cur->next = NULL;
308 cur->size = read;
309 cur->hdr = (struct nlmsghdr *)(cur + 1);
310 memcpy( cur->hdr, buf, read );
311 if (last) last->next = cur;
312 else *data = cur;
313 last = cur;
314 } while (!done);
316 HeapFree( GetProcessHeap(), 0, buf );
317 return 0;
319 fail:
320 free_netlink_reply( *data );
321 HeapFree( GetProcessHeap(), 0, buf );
322 return -1;
326 static DWORD get_indices_from_reply( struct netlink_reply *reply, int pid, int seq,
327 BOOL skip_loopback, InterfaceIndexTable *table )
329 struct nlmsghdr *hdr;
330 struct netlink_reply *r;
331 int count = 0;
333 for (r = reply; r; r = r->next)
335 int size = r->size;
336 for (hdr = r->hdr; NLMSG_OK(hdr, size); hdr = NLMSG_NEXT(hdr, size))
338 if (hdr->nlmsg_pid != pid || hdr->nlmsg_seq != seq) continue;
339 if (hdr->nlmsg_type == NLMSG_DONE) break;
341 if (hdr->nlmsg_type == RTM_NEWLINK)
343 struct ifinfomsg *info = NLMSG_DATA(hdr);
345 if (skip_loopback && (info->ifi_flags & IFF_LOOPBACK)) continue;
346 if (table) table->indexes[count] = info->ifi_index;
347 count++;
351 return count;
354 DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
356 int fd, pid, seq;
357 struct netlink_reply *reply = NULL;
358 DWORD count = 0;
360 if (table) *table = NULL;
361 fd = open_netlink( &pid );
362 if (fd < 0) return 0;
364 if (send_netlink_req( fd, pid, RTM_GETLINK, &seq ) < 0)
365 goto end;
367 if (recv_netlink_reply( fd, pid, seq, &reply ) < 0)
368 goto end;
370 count = get_indices_from_reply( reply, pid, seq, skip_loopback, NULL );
372 if (table)
374 InterfaceIndexTable *ret = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET(InterfaceIndexTable, indexes[count]) );
375 if (!ret)
377 count = 0;
378 goto end;
381 ret->numIndexes = count;
382 get_indices_from_reply( reply, pid, seq, skip_loopback, ret );
383 *table = ret;
386 end:
387 free_netlink_reply( reply );
388 close( fd );
389 return count;
392 #else
393 DWORD get_interface_indices( BOOL skip_loopback, InterfaceIndexTable **table )
395 if (table) *table = NULL;
396 return 0;
398 #endif
400 static DWORD getInterfaceBCastAddrByName(const char *name)
402 DWORD ret = INADDR_ANY;
404 if (name) {
405 int fd = socket(PF_INET, SOCK_DGRAM, 0);
407 if (fd != -1) {
408 struct ifreq ifr;
410 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
411 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
412 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
413 close(fd);
416 return ret;
419 static DWORD getInterfaceMaskByName(const char *name)
421 DWORD ret = INADDR_NONE;
423 if (name) {
424 int fd = socket(PF_INET, SOCK_DGRAM, 0);
426 if (fd != -1) {
427 struct ifreq ifr;
429 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
430 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
431 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
432 close(fd);
435 return ret;
438 #if defined (SIOCGIFHWADDR) && defined (HAVE_STRUCT_IFREQ_IFR_HWADDR)
439 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
440 PDWORD type)
442 DWORD ret;
443 int fd;
445 if (!name || !len || !addr || !type)
446 return ERROR_INVALID_PARAMETER;
448 fd = socket(PF_INET, SOCK_DGRAM, 0);
449 if (fd != -1) {
450 struct ifreq ifr;
452 memset(&ifr, 0, sizeof(struct ifreq));
453 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
454 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
455 ret = ERROR_INVALID_DATA;
456 else {
457 unsigned int addrLen;
459 switch (ifr.ifr_hwaddr.sa_family)
461 #ifdef ARPHRD_LOOPBACK
462 case ARPHRD_LOOPBACK:
463 addrLen = 0;
464 *type = MIB_IF_TYPE_LOOPBACK;
465 break;
466 #endif
467 #ifdef ARPHRD_ETHER
468 case ARPHRD_ETHER:
469 addrLen = ETH_ALEN;
470 *type = MIB_IF_TYPE_ETHERNET;
471 break;
472 #endif
473 #ifdef ARPHRD_FDDI
474 case ARPHRD_FDDI:
475 addrLen = ETH_ALEN;
476 *type = MIB_IF_TYPE_FDDI;
477 break;
478 #endif
479 #ifdef ARPHRD_IEEE802
480 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
481 addrLen = ETH_ALEN;
482 *type = MIB_IF_TYPE_TOKENRING;
483 break;
484 #endif
485 #ifdef ARPHRD_IEEE802_TR
486 case ARPHRD_IEEE802_TR: /* also Token Ring? */
487 addrLen = ETH_ALEN;
488 *type = MIB_IF_TYPE_TOKENRING;
489 break;
490 #endif
491 #ifdef ARPHRD_SLIP
492 case ARPHRD_SLIP:
493 addrLen = 0;
494 *type = MIB_IF_TYPE_SLIP;
495 break;
496 #endif
497 #ifdef ARPHRD_PPP
498 case ARPHRD_PPP:
499 addrLen = 0;
500 *type = MIB_IF_TYPE_PPP;
501 break;
502 #endif
503 default:
504 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
505 *type = MIB_IF_TYPE_OTHER;
507 if (addrLen > *len) {
508 ret = ERROR_INSUFFICIENT_BUFFER;
509 *len = addrLen;
511 else {
512 if (addrLen > 0)
513 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
514 /* zero out remaining bytes for broken implementations */
515 memset(addr + addrLen, 0, *len - addrLen);
516 *len = addrLen;
517 ret = NO_ERROR;
520 close(fd);
522 else
523 ret = ERROR_NO_MORE_FILES;
524 return ret;
526 #elif defined (SIOCGARP)
527 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
528 PDWORD type)
530 DWORD ret;
531 int fd;
533 if (!name || !len || !addr || !type)
534 return ERROR_INVALID_PARAMETER;
536 fd = socket(PF_INET, SOCK_DGRAM, 0);
537 if (fd != -1) {
538 if (isLoopbackInterface(fd, name)) {
539 *type = MIB_IF_TYPE_LOOPBACK;
540 memset(addr, 0, *len);
541 *len = 0;
542 ret=NOERROR;
544 else {
545 struct arpreq arp;
546 struct sockaddr_in *saddr;
547 struct ifreq ifr;
549 /* get IP addr */
550 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
551 ioctl(fd, SIOCGIFADDR, &ifr);
552 memset(&arp, 0, sizeof(struct arpreq));
553 arp.arp_pa.sa_family = AF_INET;
554 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
555 saddr->sin_family = AF_INET;
556 memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
557 if ((ioctl(fd, SIOCGARP, &arp)))
558 ret = ERROR_INVALID_DATA;
559 else {
560 /* FIXME: heh: who said it was ethernet? */
561 int addrLen = ETH_ALEN;
563 if (addrLen > *len) {
564 ret = ERROR_INSUFFICIENT_BUFFER;
565 *len = addrLen;
567 else {
568 if (addrLen > 0)
569 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
570 /* zero out remaining bytes for broken implementations */
571 memset(addr + addrLen, 0, *len - addrLen);
572 *len = addrLen;
573 *type = MIB_IF_TYPE_ETHERNET;
574 ret = NO_ERROR;
578 close(fd);
580 else
581 ret = ERROR_NO_MORE_FILES;
583 return ret;
585 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
586 static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
587 PDWORD type)
589 DWORD ret;
590 struct if_msghdr *ifm;
591 struct sockaddr_dl *sdl;
592 u_char *p, *buf;
593 size_t mibLen;
594 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
595 unsigned addrLen;
596 BOOL found = FALSE;
598 if (!name || !len || !addr || !type)
599 return ERROR_INVALID_PARAMETER;
601 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
602 return ERROR_NO_MORE_FILES;
604 buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
605 if (!buf)
606 return ERROR_NOT_ENOUGH_MEMORY;
608 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
609 HeapFree(GetProcessHeap(), 0, buf);
610 return ERROR_NO_MORE_FILES;
613 ret = ERROR_INVALID_DATA;
614 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
615 ifm = (struct if_msghdr *)p;
616 sdl = (struct sockaddr_dl *)(ifm + 1);
618 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
619 continue;
621 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
622 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
623 continue;
625 found = TRUE;
626 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
627 if (addrLen > *len) {
628 ret = ERROR_INSUFFICIENT_BUFFER;
629 *len = addrLen;
631 else {
632 if (addrLen > 0)
633 memcpy(addr, LLADDR(sdl), addrLen);
634 /* zero out remaining bytes for broken implementations */
635 memset(addr + addrLen, 0, *len - addrLen);
636 *len = addrLen;
637 #if defined(HAVE_NET_IF_TYPES_H)
638 switch (sdl->sdl_type)
640 case IFT_ETHER:
641 *type = MIB_IF_TYPE_ETHERNET;
642 break;
643 case IFT_FDDI:
644 *type = MIB_IF_TYPE_FDDI;
645 break;
646 case IFT_ISO88024: /* Token Bus */
647 *type = MIB_IF_TYPE_TOKENRING;
648 break;
649 case IFT_ISO88025: /* Token Ring */
650 *type = MIB_IF_TYPE_TOKENRING;
651 break;
652 case IFT_PPP:
653 *type = MIB_IF_TYPE_PPP;
654 break;
655 case IFT_SLIP:
656 *type = MIB_IF_TYPE_SLIP;
657 break;
658 case IFT_LOOP:
659 *type = MIB_IF_TYPE_LOOPBACK;
660 break;
661 default:
662 *type = MIB_IF_TYPE_OTHER;
664 #else
665 /* default if we don't know */
666 *type = MIB_IF_TYPE_ETHERNET;
667 #endif
668 ret = NO_ERROR;
671 HeapFree(GetProcessHeap(), 0, buf);
672 return ret;
674 #endif
676 DWORD getInterfacePhysicalByIndex(IF_INDEX index, PDWORD len, PBYTE addr,
677 PDWORD type)
679 char nameBuf[IF_NAMESIZE];
680 char *name = getInterfaceNameByIndex(index, nameBuf);
682 if (name)
683 return getInterfacePhysicalByName(name, len, addr, type);
684 else
685 return ERROR_INVALID_DATA;
688 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
690 DWORD ret;
691 int fd;
693 if (!name)
694 return ERROR_INVALID_PARAMETER;
695 if (!mtu)
696 return ERROR_INVALID_PARAMETER;
698 fd = socket(PF_INET, SOCK_DGRAM, 0);
699 if (fd != -1) {
700 struct ifreq ifr;
702 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
703 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
704 ret = ERROR_INVALID_DATA;
705 else {
706 #ifndef __sun
707 *mtu = ifr.ifr_mtu;
708 #else
709 *mtu = ifr.ifr_metric;
710 #endif
711 ret = NO_ERROR;
713 close(fd);
715 else
716 ret = ERROR_NO_MORE_FILES;
717 return ret;
720 DWORD getInterfaceStatusByName(const char *name, INTERNAL_IF_OPER_STATUS *status)
722 DWORD ret;
723 int fd;
725 if (!name)
726 return ERROR_INVALID_PARAMETER;
727 if (!status)
728 return ERROR_INVALID_PARAMETER;
730 fd = socket(PF_INET, SOCK_DGRAM, 0);
731 if (fd != -1) {
732 struct ifreq ifr;
734 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
735 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
736 ret = ERROR_INVALID_DATA;
737 else {
738 if (ifr.ifr_flags & IFF_UP)
739 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
740 else
741 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
742 ret = NO_ERROR;
744 close(fd);
746 else
747 ret = ERROR_NO_MORE_FILES;
748 return ret;
751 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
753 BYTE addr[MAX_INTERFACE_PHYSADDR];
754 DWORD ret, len = sizeof(addr), type;
756 if (!name)
757 return ERROR_INVALID_PARAMETER;
758 if (!entry)
759 return ERROR_INVALID_PARAMETER;
761 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
762 WCHAR *assigner;
763 const char *walker;
765 memset(entry, 0, sizeof(MIB_IFROW));
766 for (assigner = entry->wszName, walker = name; *walker;
767 walker++, assigner++)
768 *assigner = *walker;
769 *assigner = 0;
770 getInterfaceIndexByName(name, &entry->dwIndex);
771 entry->dwPhysAddrLen = len;
772 memcpy(entry->bPhysAddr, addr, len);
773 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
774 entry->dwType = type;
775 /* FIXME: how to calculate real speed? */
776 getInterfaceMtuByName(name, &entry->dwMtu);
777 /* lie, there's no "administratively down" here */
778 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
779 getInterfaceStatusByName(name, &entry->dwOperStatus);
780 /* punt on dwLastChange? */
781 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
782 memcpy(entry->bDescr, name, entry->dwDescrLen);
783 entry->bDescr[entry->dwDescrLen] = '\0';
784 entry->dwDescrLen++;
785 ret = NO_ERROR;
787 else
788 ret = ERROR_INVALID_DATA;
789 return ret;
792 static DWORD getIPAddrRowByName(PMIB_IPADDRROW ipAddrRow, const char *ifName,
793 const struct sockaddr *sa)
795 DWORD ret, bcast;
797 ret = getInterfaceIndexByName(ifName, &ipAddrRow->dwIndex);
798 memcpy(&ipAddrRow->dwAddr, sa->sa_data + 2, sizeof(DWORD));
799 ipAddrRow->dwMask = getInterfaceMaskByName(ifName);
800 /* the dwBCastAddr member isn't the broadcast address, it indicates whether
801 * the interface uses the 1's broadcast address (1) or the 0's broadcast
802 * address (0).
804 bcast = getInterfaceBCastAddrByName(ifName);
805 ipAddrRow->dwBCastAddr = (bcast & ipAddrRow->dwMask) ? 1 : 0;
806 /* FIXME: hardcoded reasm size, not sure where to get it */
807 ipAddrRow->dwReasmSize = 65535;
808 ipAddrRow->unused1 = 0;
809 ipAddrRow->wType = 0;
810 return ret;
813 #ifdef HAVE_IFADDRS_H
815 /* Counts the IPv4 addresses in the system using the return value from
816 * getifaddrs, returning the count.
818 static DWORD countIPv4Addresses(struct ifaddrs *ifa)
820 DWORD numAddresses = 0;
822 for (; ifa; ifa = ifa->ifa_next)
823 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET)
824 numAddresses++;
825 return numAddresses;
828 DWORD getNumIPAddresses(void)
830 DWORD numAddresses = 0;
831 struct ifaddrs *ifa;
833 if (!getifaddrs(&ifa))
835 numAddresses = countIPv4Addresses(ifa);
836 freeifaddrs(ifa);
838 return numAddresses;
841 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
843 DWORD ret;
845 if (!ppIpAddrTable)
846 ret = ERROR_INVALID_PARAMETER;
847 else
849 struct ifaddrs *ifa;
851 if (!getifaddrs(&ifa))
853 DWORD size = sizeof(MIB_IPADDRTABLE);
854 DWORD numAddresses = countIPv4Addresses(ifa);
856 if (numAddresses > 1)
857 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
858 *ppIpAddrTable = HeapAlloc(heap, flags, size);
859 if (*ppIpAddrTable)
861 DWORD i = 0;
862 struct ifaddrs *ifp;
864 ret = NO_ERROR;
865 (*ppIpAddrTable)->dwNumEntries = numAddresses;
866 for (ifp = ifa; !ret && ifp; ifp = ifp->ifa_next)
868 if (!ifp->ifa_addr || ifp->ifa_addr->sa_family != AF_INET)
869 continue;
871 ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifp->ifa_name,
872 ifp->ifa_addr);
873 i++;
875 if (ret)
876 HeapFree(GetProcessHeap(), 0, *ppIpAddrTable);
878 else
879 ret = ERROR_OUTOFMEMORY;
880 freeifaddrs(ifa);
882 else
883 ret = ERROR_INVALID_PARAMETER;
885 return ret;
888 ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
890 struct ifaddrs *ifa;
891 ULONG ret;
893 if (!getifaddrs(&ifa))
895 struct ifaddrs *p;
896 ULONG n;
897 char name[IFNAMSIZ];
899 getInterfaceNameByIndex(index, name);
900 for (p = ifa, n = 0; p; p = p->ifa_next)
901 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
902 !strcmp(name, p->ifa_name))
903 n++;
904 if (n)
906 *addrs = HeapAlloc(GetProcessHeap(), 0, n * (sizeof(SOCKET_ADDRESS) +
907 sizeof(struct WS_sockaddr_in6)));
908 if (*addrs)
910 struct WS_sockaddr_in6 *next_addr = (struct WS_sockaddr_in6 *)(
911 (BYTE *)*addrs + n * sizeof(SOCKET_ADDRESS));
913 for (p = ifa, n = 0; p; p = p->ifa_next)
915 if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET6 &&
916 !strcmp(name, p->ifa_name))
918 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ifa_addr;
920 next_addr->sin6_family = WS_AF_INET6;
921 next_addr->sin6_port = addr->sin6_port;
922 next_addr->sin6_flowinfo = addr->sin6_flowinfo;
923 memcpy(&next_addr->sin6_addr, &addr->sin6_addr,
924 sizeof(next_addr->sin6_addr));
925 next_addr->sin6_scope_id = addr->sin6_scope_id;
926 (*addrs)[n].lpSockaddr = (LPSOCKADDR)next_addr;
927 (*addrs)[n].iSockaddrLength = sizeof(struct WS_sockaddr_in6);
928 next_addr++;
929 n++;
932 *num_addrs = n;
933 ret = ERROR_SUCCESS;
935 else
936 ret = ERROR_OUTOFMEMORY;
938 else
940 *addrs = NULL;
941 *num_addrs = 0;
942 ret = ERROR_SUCCESS;
944 freeifaddrs(ifa);
946 else
947 ret = ERROR_NO_DATA;
948 return ret;
951 #else
953 /* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
954 * the count to you in *pcAddresses. It also returns to you the struct ifconf
955 * used by the call to ioctl, so that you may process the addresses further.
956 * Free ifc->ifc_buf using HeapFree.
957 * Returns NO_ERROR on success, something else on failure.
959 static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
961 DWORD ret;
962 int fd;
964 fd = socket(PF_INET, SOCK_DGRAM, 0);
965 if (fd != -1) {
966 int ioctlRet = 0;
967 DWORD guessedNumAddresses = 0, numAddresses = 0;
968 caddr_t ifPtr;
969 int lastlen;
971 ret = NO_ERROR;
972 ifc->ifc_len = 0;
973 ifc->ifc_buf = NULL;
974 /* there is no way to know the interface count beforehand,
975 so we need to loop again and again upping our max each time
976 until returned is constant across 2 calls */
977 do {
978 lastlen = ifc->ifc_len;
979 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
980 if (guessedNumAddresses == 0)
981 guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
982 else
983 guessedNumAddresses *= 2;
984 ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
985 ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
986 ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
987 } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
989 if (ioctlRet == 0) {
990 ifPtr = ifc->ifc_buf;
991 while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
992 struct ifreq *ifr = (struct ifreq *)ifPtr;
994 if (ifr->ifr_addr.sa_family == AF_INET)
995 numAddresses++;
997 ifPtr += ifreq_len((struct ifreq *)ifPtr);
1000 else
1001 ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
1002 if (!ret)
1003 *pcAddresses = numAddresses;
1004 else
1006 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
1007 ifc->ifc_buf = NULL;
1009 close(fd);
1011 else
1012 ret = ERROR_NO_SYSTEM_RESOURCES;
1013 return ret;
1016 DWORD getNumIPAddresses(void)
1018 DWORD numAddresses = 0;
1019 struct ifconf ifc;
1021 if (!enumIPAddresses(&numAddresses, &ifc))
1022 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
1023 return numAddresses;
1026 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
1028 DWORD ret;
1030 if (!ppIpAddrTable)
1031 ret = ERROR_INVALID_PARAMETER;
1032 else
1034 DWORD numAddresses = 0;
1035 struct ifconf ifc;
1037 ret = enumIPAddresses(&numAddresses, &ifc);
1038 if (!ret)
1040 DWORD size = sizeof(MIB_IPADDRTABLE);
1042 if (numAddresses > 1)
1043 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
1044 *ppIpAddrTable = HeapAlloc(heap, flags, size);
1045 if (*ppIpAddrTable) {
1046 DWORD i = 0;
1047 caddr_t ifPtr;
1049 ret = NO_ERROR;
1050 (*ppIpAddrTable)->dwNumEntries = numAddresses;
1051 ifPtr = ifc.ifc_buf;
1052 while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
1053 struct ifreq *ifr = (struct ifreq *)ifPtr;
1055 ifPtr += ifreq_len(ifr);
1057 if (ifr->ifr_addr.sa_family != AF_INET)
1058 continue;
1060 ret = getIPAddrRowByName(&(*ppIpAddrTable)->table[i], ifr->ifr_name,
1061 &ifr->ifr_addr);
1062 i++;
1064 if (ret)
1065 HeapFree(GetProcessHeap(), 0, *ppIpAddrTable);
1067 else
1068 ret = ERROR_OUTOFMEMORY;
1069 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
1072 return ret;
1075 ULONG v6addressesFromIndex(IF_INDEX index, SOCKET_ADDRESS **addrs, ULONG *num_addrs)
1077 *addrs = NULL;
1078 *num_addrs = 0;
1079 return ERROR_SUCCESS;
1082 #endif
1084 char *toIPAddressString(unsigned int addr, char string[16])
1086 if (string) {
1087 struct in_addr iAddr;
1089 iAddr.s_addr = addr;
1090 /* extra-anal, just to make auditors happy */
1091 lstrcpynA(string, inet_ntoa(iAddr), 16);
1093 return string;